2011-01-18 2 views
4

私はリアルタイムでビデオを処理するプログラムに取り組んでいます。QThreadsの並行性に問題があります。同じ信号を受け取っているスレッドがお互いをブロックしています

私のシステムはかなりこのように設定されています

  DataSourceThread 
      / \ 
      /  \ 
     /  \ 
    Receiver  Receiver 
     /   \ 
     /    \ 
    /    \ 
Processor1   Processor2 

(。すべてのこれらのクラスはQThreadを拡張している)

のでDataSourceThreadは、ビデオストリームからフレームをフェッチし、フレームを含む信号を発します受信機。 接続タイプ:Qt :: DirectConnection

受信者は、基本的にDataSourceThreadによって送信されたフレームを受信し、前のフレームの処理が完了すると、そのフレームを含む信号をプロセッサに送信します。 接続タイプ:Qt :: QueuedConnection。 プロセッサが前のフレームの処理を完了していない場合は、信号を出力せずに戻ります(フレームをスキップします)。

これが動作するかどうかをテストするには、Processor1がフレームを受信して​​Processor2がメッセージを出力するだけです。QThread :: sleep(3);とメッセージを印刷します。

(レシーバはまた、プロセッサに渡す前に、フレームのディープコピーを行います。)

期待される結果:

プロセッサ1は常にメッセージを印刷する必要があります。 Processor2は3秒ごとにメッセージを出力する必要があります。

問題:

両方のプロセッサは、同じ時間(3秒ごと)で彼らのメッセージを印刷します。 Processor1は、メッセージの印刷前にProcessor2が完了するまで待機します。 出力はこれとほぼ同じです:

"Message from processor1" 
"Message from processor2" 
"Message from processor1" 
"Message from processor2" 
"Message from processor1" 
"Message from processor2" 

などです。

私はここでアイデアが不足しているので、 だから、どんな助けでも大歓迎です!

EDIT:

main.cppに:DataSourceThread.cppから

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 

    DataSourceThread dataSourceThread; 
    dataSourceThread.start(); 

    GUIThread *guiProcessor = new GUIThread(); 
    FrameReceiver *guiReceiver = new FrameReceiver(guiProcessor, 0); 

    QObject::connect(
     &dataSourceThread, SIGNAL(frameReceived(Frame*)), 
     guiReceiver, SLOT(receive(Frame*)), 
     Qt::DirectConnection 
    ); 

    DetectorThread *detectorProcessor = new DetectorThread(); 
    FrameReceiver *detectorReceiver = new FrameReceiver(detectorProcessor, 0); 

    QObject::connect(
     &dataSourceThread, SIGNAL(frameReceived(Frame*)), 
     detectorReceiver, SLOT(receive(Frame*)), 
     Qt::DirectConnection 
    ); 

    return app.exec(); 
} 

は、ここでは、コードの一部です

void DataSourceThread::run() 
{ 
    ... stuff ... 

    while (true) { 
     image = cvQueryFrame(capture); 

     if (!image) { 
      qDebug() << QString("Could not capture frame"); 
      continue; 
     } 

     cvReleaseImage(&temp_image); 
     temp_image = cvCreateImage(cvSize(640, 480), image->depth, 3); 

     cvResize(image, temp_image, 1); 

     frame->lock(); 
     frame->setImage(temp_image); 
     frame->unlock(); 

     emit frameReceived(frame); 

     msleep(1); 
    } 
} 

FrameReceiver .cppファイル:

FrameReceiver::FrameReceiver(FrameProcessor* processor, QObject *parent) : QThread(parent) { 
    m_ready = true; 

    m_processor = processor; 
    m_processor->start(); 

    QObject::connect(
     (QObject*)this, SIGNAL(frameReceived(Frame*)), 
     m_processor, SLOT(receive(Frame*)), 
     Qt::QueuedConnection 
    ); 

    QObject::connect(
     m_processor, SIGNAL(ready()), 
     (QObject*)this, SLOT(processCompleted()), 
     Qt::DirectConnection 
    ); } 

void FrameReceiver::processCompleted() { 
    m_ready = true; } 

void FrameReceiver::receive(Frame *frame) { 
    if (m_ready == true) { 
     m_ready = false; 
     frame->lock(); 
     Frame *f = new Frame(*frame); 
     frame->unlock(); 
     emit frameReceived(f); 
    } else { 
     // SKIPPED THIS FRAME 
    } 
} 

GUIThread。CPP:(プロセッサ1)

GUIThread::GUIThread(QObject *parent) : FrameProcessor(parent) 
{ 
    m_frame = new Frame(); 
} 

void GUIThread::setFrame(Frame *frame) 
{ 
    qDebug() << QString("Guithread received frame"); 
}  

FrameProcessor.cpp

// (The processors extend this class) 
void FrameProcessor::receive(Frame *frame) 
{ 
    setFrame(frame); 
    delete frame; 
    emit ready(); 
} 

DetectorThread(Processor2)はguithreadと同様にしたが、setFrameで3秒間スリープ有します。

+1

どのように信号を送信しますか – osgx

+1

いくつかのコードを表示してください。 –

+0

私のDataSourceThreadで私はこうします:emit frameReceived(frame);受信側ではフレームをコピーして次のようにします。emit frameReceived(copied_frame); – Pandafox

答えて

3

問題の一部は、すべてのQObjectがメインのアプリケーションスレッドによって所有されていると思います。これは、非同期信号を配信するためのイベントループを1つ共有し、処理チェーン全体を効果的にシリアライズすることを意味します。

私はこれを設定する適切な方法のようなものだと思う:あなたはそれをあなたがいることを確実にしたい場合、私はスレッド間DirectConnectionを使用していない提案ではなく、BlockingQueuedConnectionでしょうこの方法を行う場合

GUIProcessor *guiProcessor = new GUIProcessor(); 
QThread guiProcessorThread; 
guiProcessor.moveToThread(&guiProcessorThread); 

FrameReceiver *guiReceiver = new FrameReceiver(guiProcessor, 0); 
QThread guiReceiverThread; 
guiReceiver.moveToThread(&guiReceiverThread); 

guiProcessorThread.start(); 
guiReceiverThread.start(); 

現在のフレームは、次のフレームをキャプチャする前に処理されます。 http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

そして、この:このことができますhttp://labs.qt.nokia.com/2006/12/04/threading-without-the-headache/

希望

はこれを参照してください!

編集:私の提案では、あなたのクラスはQThreadの代わりにQObjectを継承することを明確にするために、

+0

本当にありがとう、あなたは本当の命を救う人です!あなたの提案は魅力的に機能しました! – Pandafox

関連する問題