0

Qt Fortune Threaded Server の例を変更して、接続からテキストを読み取り、それをエコー バックしようとしています。FortuneThread.h ファイルで tcpSocket を次のように定義しました。

QTcpSocket tcpSocket;

スレッドの新しい実行関数は次のようになります。

void FortuneThread::run()
{
    if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
        emit error(tcpSocket.error());
        return;
    }
    connect(&tcpSocket, SIGNAL(readyREAD()), this, SLOT(readCommand()) );
}

コンパイルして実行しますが、接続すると次のエラーが発生します(接続行を参照):

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x1eeb920), parent's thread is QThread(0x1bb3f90), current thread is FortuneThread(0x1eeb8f0)
QObject::connect: No such signal QTcpSocket::readyREAD() in ../fortune/fortunethread.cpp:60

誰かが私に原因を説明できますか? tcpSocket は FortuneThread クラス (別のスレッドとして実行される) 内で定義されており、"this" は FortuneThread を参照しているため、両方のオブジェクトがスレッド内にあると思いますか? これを修正する方法は?

4

3 に答える 3

4

ソケット オブジェクトはメイン スレッドで作成されていますが、別のスレッドからアクセスしています。run()スレッドのメソッド内で作成する必要があります。ソケットが定義されている場所は問題ではありません。C++ ランタイム ライブラリが静的オブジェクトの初期化を行っているときに、メイン スレッドから作成されます。

QTcpSocket * tcpSocket;

...

void FortuneThread::run() {
  tcpSocket = new QTcpSocket;
  ...
}
于 2013-09-27T03:19:02.663 に答える
2

私はクバ・オーバーに同意します。Qt スレッド、オブジェクト、およびイベントに関する優れたガイドを読む必要があります。特に、スレッド全体のシグナルとスロットと呼ばれるセクション。著者は、コントローラとワーク パーツを異なるエッセンスに分割することを推奨しています。

コードの 2 番目の問題 — 大文字と小文字を区別するシグナル名。に変更しreadyReadます。

于 2013-09-27T06:35:50.320 に答える
1

Qt Fortune Threaded Server の例の問題は、スレッドの使用方法にあります。Qt の開発者が言うように、「あなたのやり方は間違っている」

問題は QThread の継承です。QThread クラスは実際にはスレッドではありませんが、スレッド コントローラー クラスであり、これを継承する唯一の理由は、スレッドを制御する動作を変更する場合です。

表示されている問題は、スレッド アフィニティが原因です。オブジェクトが属するスレッド。

スレッドが次のように継承されている場合: -

class FortuneThread : public QThread
{
    Q_OBJECT

    private:
        QTcpSocket tcpSocket;
};

次に、FortuneThread のオブジェクトがメイン スレッドからインスタンス化されます。

FortuneThread* ft = new FortuneThread(parent);

スレッドとスレッドがインスタンス化したオブジェクト (tcpSocket) のスレッド アフィニティがメイン スレッドになったため、tcpSocket はメイン スレッドで実行されており、これがエラーの内容です。run 関数が呼び出された時点で、接続は FortuneThread から行われていますが、tcpSocket はメイン スレッドにあります。

これを解決するより良い方法は、QObject から派生したクラスを作成し、それをスレッドに移動することです: -

// Inherit from QObject, not QThread
class FortuneSocket : public QObject
{
    Q_OBJECT

    public slots:
       void Run();
    private:
        QTcpSocket tcpSocket;
};


QThread* pThread = new QThread(parent);
FortuneSocket* pFortune = new FortuneSocket(parent);

connect(pThread, &QThread::started, pFortune, &FortuneSocket::Run); // Qt5 connect style

// move the fortune socket to the thread: -
pFortune->moveToThread(pThread);

ここで、pThread->start() でスレッドを開始すると、FortuneSocket オブジェクトとそのすべてのメンバーが新しいスレッドで実行されます。

このようにスレッドを使用すると、スレッドごとに 1 つのオブジェクトを保持するのではなく、複数のオブジェクトを 1 つのスレッドに移動できることも意味します。CPU コアよりも多くのスレッドを作成しても意味がないことに注意してください。

最後に、QThread の使用方法に関するより詳細な記事がここにあります。

于 2013-09-27T08:15:30.423 に答える