Concurrency problems with QThreads. Threads that receive the same signal block each other

So, I’m working on a program that processes video in real time, and I am having problems with the threads blocking each other.

My system is pretty much configured as follows:

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

(All of these classes extend QThread.)

So, DataSourceThread extracts frames from the video stream and emits a signal containing the frame to the receivers. Connection Type: Qt :: DirectConnection

The receivers basically receive the frames sent by the DataSourceThread, and if the processor processes the previous frame, it will emit a signal containing the frame to the Processor. Connection Type: Qt :: QueuedConnection. If the processor has not finished processing the previous frame, it will simply return without radiation (frame skipping).

To check if this works, all I did was make Processor1 just print the message when it receives the frame, and Processor2 QThread :: sleep (3); and print the message.

(Receivers will also make a deep copy of the frame before transmitting it to the processors.)

Expected Result:

Processor1 must constantly print messages. Processor2 should print a message every 3 seconds.

Problem:

Both processors print their messages at the same time (every 3 seconds). Processor1 waits for Processor2 to execute before printing its message. So the result looks something like this:

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

etc.

I'm running out of ideas here, so any help would be greatly appreciated!

EDIT: Here are some of the code:

main.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(); } 

From 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: (Processor1)

 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) does the same as guithread, but with a 3 second sleep in setFrame.

+4
source share
1 answer

I think part of the problem is that all your QObjects belong to the main thread of the application. This means that they all use the same event loop to deliver asynchronous signals, effectively serializing the entire processing chain.

I think the correct way to fix this would be as follows:

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

If you do this like this, I would suggest not using DirectConnection between threads, but rather BlockingQueuedConnection , if you want to make sure that the current frame is processed before you capture the next one.

See this: http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

And this: http://labs.qt.nokia.com/2006/12/04/threading-without-the-headache/

Hope this helps!

EDIT: To be clear, with my suggestion, your classes inherit from QObject instead of QThread.

+3
source

Source: https://habr.com/ru/post/1336030/


All Articles