【问题标题】:Concurrency issues with QThreads. Threads receiving the same signal are blocking each otherQThreads 的并发问题。接收相同信号的线程相互阻塞
【发布时间】:2011-01-18 18:44:45
【问题描述】:

所以我正在开发一个实时处理视频的程序,但我遇到了线程“阻塞”彼此的问题。

我的系统基本上是这样设置的:

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

(所有这些类都扩展了 QThread。)

因此,DataSourceThread 从视频流中获取帧并将包含该帧的信号发送到接收器。 连接类型:Qt::DirectConnection

接收器基本上接收由 DataSourceThread 发出的帧,如果处理器完成对前一帧的处理,它将向处理器发出包含该帧的信号。 连接类型:Qt::QueuedConnection。 如果处理器没有完成对前一帧的处理,它将直接返回而不发出信号(跳帧)。

为了测试这是否有效,我所做的只是让 Processor1 在收到帧时打印一条消息,而 Processor2 执行 QThread::sleep(3); 并打印一条消息.

(在将帧传递给处理器之前,接收者还将对帧进行深度复制。)

预期结果:

Processor1 应该不断地打印消息。 处理器 2 应该每 3 秒打印一条消息。

问题:

两个处理器同时打印它们的消息(每 3 秒)。 Processor1 等到 Processor2 完成后再打印它的消息。 所以输出几乎是这样的:

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

等等。

我的想法已经用完了, 所以任何帮助将不胜感激!

编辑: 以下是部分代码:

ma​​in.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();
}  

来自 DataSourceThread.cpp:

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 秒。

【问题讨论】:

  • 在我的 DataSourceThread 我做:发出 frameReceived(frame);在接收器中我复制帧并执行:发出 frameReceived(copied_frame);
  • FrameProcessor 是否继承自 QThread?如果是这样,您是重写 run() 还是使用默认实现?
  • FrameProcessor 确实继承自 QThread,但不会覆盖 run()
  • 你在任何地方调用 QThread::moveToThread() 吗?
  • 不,我贴在这里的代码应该有我项目中所有线程相关的代码。

标签: c++ multithreading qt concurrency qthread


【解决方案1】:

我认为部分问题在于您的所有 QObject 都归主应用程序线程所有。这意味着它们都共享一个事件循环来传递异步信号,从而有效地序列化整个处理链。

我认为正确的设置方法如下:

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

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

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

如果你这样做,我建议不要在线程之间使用DirectConnection,而是使用BlockingQueuedConnection,如果你想确保在捕获下一帧之前处理当前帧。

看到这个:http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

还有这个:http://labs.qt.nokia.com/2006/12/04/threading-without-the-headache/

希望这会有所帮助!

编辑:明确地说,根据我的建议,您的类将继承 QObject 而不是 QThread。

【讨论】:

  • 非常感谢,您是真正的救星!你的建议就像一个魅力!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多