0

特定の時点で複数のスレッドが開始されるようにする、Qt 用のバリアのような同期プリミティブを作成しようとしています。ただし、シグナル (started() など) が機能しない場合に状況が発生するようです。

コードを縮小して、最小限の (非) 動作例をコンパイルしようとしました。

========
main.cpp
========
#include <QtCore>
#include <QCoreApplication>

#include "qmultithreadwaiter.hpp"
#include <QSignalMapper>
#include <qdebug.h>

#define dlog qDebug()

class Test: public QThread {

public:
   virtual void run( ) {
      QThread::sleep( 500 );
   }
};

int main( int argc, char *argv[ ] ) {
   QCoreApplication a( argc, argv );
   Test t1, t2;
   QMultiThreadWaiter w;
   w.addThread(1, &t1);
   w.addThread(2, &t2);

   t1.start();
   t2.start();

   w.wait4all();
   dlog << "Wait completed";

   return 0;
}

=========================
qmultithreadwaiter.hpp
=========================    
// Qt includes
#include <QSignalMapper>
#include <QMap>
#include <QThread>

class QMultiThreadWaiter: public QThread {
Q_OBJECT

   QMap < int, bool > started;
   QSignalMapper sm;

private slots:
   void threadStarted( int id );
   void someThreadStarted();

signals:
   void allStarted( );

public:
   QMultiThreadWaiter( );

   void addThread( int id, QThread* t );
   void wait4all( );

};
=================
qmultithreadwaiter.cpp
=================
#include "qmultithreadwaiter.hpp"

// Qt includes
#include <QThread>
// Debug includes
#include <qdebug.h>

#define dlog qDebug()

// Project includes

void QMultiThreadWaiter::threadStarted( int id ) {
   dlog << "Thread #" << id << " started!";
   started[ id ] = true;
   QMapIterator < int, bool > mi( started );
   while ( mi.hasNext( ) ) {
      mi.next( );
      if ( !mi.value( ) )
         return;
   }

   dlog << "All threads started!";

   // All threads are started
   emit allStarted( );
}

void QMultiThreadWaiter::addThread( int id, QThread* t ) {
   dlog << "Adding thread " << t << " with id " << id;
   sm.setMapping( t, id );
   connect( t, SIGNAL(started()), &sm, SLOT(map()), Qt::QueuedConnection );
   connect( t, SIGNAL(started()), this, SLOT(someThreadStarted()),
            Qt::QueuedConnection );
}
void QMultiThreadWaiter::wait4all( ) {
   dlog << "Starting this thread";
   start( );
   dlog << "Going to wait";
   wait( );
   dlog << "Wait finished";
}

QMultiThreadWaiter::QMultiThreadWaiter( ) {
   sm.moveToThread( this );
   connect( &sm, SIGNAL(mapped(int)), this, SLOT(threadStarted(int)),
            Qt::QueuedConnection );
   connect( this, SIGNAL(allStarted()), this, SLOT(quit()),
            Qt::QueuedConnection );
   connect( this, SIGNAL(started()), this, SLOT( someThreadStarted()),
            Qt::QueuedConnection );
}

void QMultiThreadWaiter::someThreadStarted( ) {
   dlog << "Some thread started!";
}

出力:

Adding thread  QThread(0x28fefc)  with id  1 
Adding thread  QThread(0x28fef4)  with id  2 
Starting this thread 
Going to wait
<stuck>

奇妙なのは、さえsomeThreadStarted()求められていないことですthis。お知らせ下さい。

4

1 に答える 1

0

イベントループが実行されているスレッドはありません。w.wait4all();からを呼び出すとmain()、実行が に到達するとメイン スレッドがブロックされますwait()。を使用Qt::QueuedConnectionしてシグナルを接続すると、ターゲット スレッドのコントロールがイベント ループに戻ったときにスロットが呼び出されますが、これはテスト スレッド用ではありません。一方、メイン スレッドは でブロックされwait()ており、イベント ループもありません (QCoreApplication::exec()は呼び出されません)。メインスレッドは、受信したキューに入れられたシグナルも処理できません。そのため、thisスレッドも発行していないようですstarted()

于 2012-11-20T04:21:01.727 に答える