0

あるプロジェクトをやっていたときに重大な間違いを犯したので、下から再プログラムする必要があります。接続やリクエストなどを処理するマルチスレッドサーバーを作成しています。しかし、ベースを使用して新しいクラスを作成したときQThreadのオブジェクトで、QThread-> start()ではなくQThread-> run()でスレッドを開始していました。今、私はたくさんのエラーを受け取ります。これが状況です。接続ごとに新しいスレッドを作成し、接続されている各クライアントからデータの読み取りを開始するサーバーがあります。データを受信すると、メインGUIクラスに接続されている信号を送信し、結果OKを表示します。また、メッセージに返信するためのソケットハンドルも保存されます。GUIクラスからソケットにデータを書き込むと、次のようになります。

QObject:別のスレッドにある親の子を作成できません。(親はQNativeSocketEngine(0x23a6c38)、親のスレッドはMyThread(0x1fb8670)、現在のスレッドはQThread(0x9eb980)

どうしたの?

4

1 に答える 1

1

私はQTを知っていますが、QTソケットの実装自体には詳しくありませんが、エラーメッセージの音と設計の説明から、問題はQTではなく、スレッド/ソケットアーキテクチャ全般に関係しています。マルチスレッドアプリケーションでは、慎重に考えられたインテリジェントデザインが効率的であり、セッションデータなどの一貫性が保たれ、同時実行の問題や孤立したデータ構造などに悩まされないようにする必要があります。

また、メッセージに返信するためのソケットハンドルも保存されます。GUIクラスからソケットにデータを書き込むと、次のように表示されます...:

実装の詳細をすべて知らずに、スレッド1のソケットハンドルを永続化してスレッド1の呼び出しに応答し、スレッド2を使用して呼び出しからデータを書き込もうとした場合、元のソケットハンドルは無効になります。スレッド2のコンテキスト。これにより、エラーメッセージが説明される場合があります。

後続の呼び出しのためにソケットハンドルを保持することは、さまざまな理由(発生している問題を含む)で物事を行うための良い方法ではありません。なぜそれを行うのですか?呼び出し間でクライアント情報を永続化する必要がある場合は、セッション構造を使用してそのデータを永続化します。会話が続いている間、スレッド全体を存続させたい場合は、スレッドとソケットの相互作用がそのように動作するように設計し、スレッドプールなどを検討してください。ただし、孤立したソケットをぶら下げてはいけません。独自のスレッドコンテキストであり、「ホーム」スレッドの外部に有効なハンドルがありません。

ソケットが会話を終了すると、生成されたスレッドと、会話を続行するためにそのスレッドで作成されたソケットが完了します。すべてをクリーンアップする必要があります。

私があなたの実装を正しく理解していれば、私の提案はあなたの問題を解決するはずです。

あなたのコメントであなたは言及します:

「グローバル変数としてのソケット」-私があなたがしていることを正しく理解しているのであれば、そのような方法でグローバルソケットを使用するべきではありません。

サーバーアプリには、リクエストをリッスンする永続ソケットを備えたメインスレッドが必要です。リクエストが着信すると、シグナルが発行され、そのシグナルのスロットが、そのリクエストを処理するための新しいソケットを初期化するスレッドを生成する必要があります。スレッドでリクエストを処理してから、すべてをクリーンアップします。

着信要求から情報を抽出してどこかに永続化する必要がある場合は、メインスレッドで実行し、他のスレッドは、メインスレッドでそのセッションを永続化するために使用する構造にアクセスできないようにする必要があります(同期メカニズムを使用しない場合)同じことリクエスト処理が完了したときに情報を取得したい場合は、スレッドが終了したときに発行される信号を介して、生成されたスレッドからメインスレッドに情報を戻します。

これらのルールに従わない場合は、同期オブジェクトを使用する必要があります。そうしないと、エラーメッセージの音から判断して、発生していることを含め、あらゆる種類の問題が発生します。

要するに:「スレッドで何が起こるか、スレッドにとどまる」

于 2013-01-08T07:56:45.713 に答える