Qt 中两个线程之间的事件同步

Event synchronization between two threads in Qt

本文关键字:之间 线程 事件 同步 两个 Qt      更新时间:2023-10-16

我有两个线程,假设线程"A"和线程"B"。线程"A"帖子的自定义QEvent到线程"B",然后它应该等到线程"B"处理此事件。

到目前为止我做了什么:

我的活动类:

class IPCMessageEvent : public QEvent
{
public:
   IPCMessageEvent(QWaitCondition* pConditions) : QEvent(IPC_MESSAGE_RECEIVED)
                                                , mpWaitCondition(pConditions)
   { };
   ~IPCMessageEvent()
   {
      mpWaitCondition->wakeOne();
   };
private:
   QWaitCondition* mpWaitCondition;
};

我的线程"A":

QWaitCondition recvCondition;
IPCMessageEvent* pEvent = new IPCMessageEvent(&recvCondition);
QCoreApplication::postEvent(gpApp, pEvent);
QMutex  mutex; 
        mutex.lock();
recvCondition.wait(&mutex, IPC_MESSAGE_WAIT_TIMEOUT);

我的线程"B":处理收到的事件并销毁它。~IPCMessageEvent 析构函数被调用,因此将为线程"A"中的recvCondition启动wakeOne()

一切似乎都很好,这只是一件事!看起来有时~IPCMessageEvent的调用比预期的要早...

QCoreApplication::postEvent(gpApp, pEvent);
<---- pEvent is already destroyed here ---->
QMutex mutex; 
       mutex.lock();

所以我的recvCondition.wait(&mutex, IPC_MESSAGE_WAIT_TIMEOUT);将被锁定并达到超时。

还有其他方法可以进行这种同步吗?或者也许有人有任何建议如何解决/克服这个问题?

嗯,你有一个经典的竞争条件。您的线程 A 可能会在发布事件后直接中断,然后线程 B 处理并销毁它。由于条件变量的通知只有在有人已经在等待时才有效,因此您会无限地错过通知,从而错过您的块。

因此,您需要在发布事件之前锁定互斥锁。但是,这要求线程 B 在处理事件时还需要锁定此互斥锁。否则,您无法阻止争用条件,因为线程 B 没有理由等待任何事情(或者知道它应该"等待"到线程 A 准备好等待条件变量)。

另类:

如果在两个线程

(或位于两个线程中的对象)之间使用信号/插槽连接,则可以使用 Qt::BlockingQueuedConnection 。这可确保线程 A 在发出信号后阻塞,直到线程 B 中的事件循环处理它。

谢谢约翰内斯,我真的需要尝试使用您建议的信号/插槽替代方案。

我现在做的是:我创建了一个 QMutex 和布尔标志,用于线程"A"和线程"B"之间。

bool    mIsProcessingMessage;
QMutex  mIsProcessingMessageLock;

在线程"A"中,我像这样发布我的事件:

IPCMessageEvent* pEvent = new IPCMessageEvent();
{   // Inform everyone that we will be processing our message.
    QMutexLocker locker(&mIsProcessingMessageLock);
    mIsProcessingMessage = true;
};
QCoreApplication::postEvent(gpApp, pEvent, Qt::HighEventPriority);
forever  // Loop until event will get processed.
{
    QMutexLocker locker(&mIsProcessingMessageLock);
    if (mIsProcessingMessage == false)
       break;
    ::Sleep(2);  // Don't load up the CPU.
};

在线程"B"中,当我的事件被处理时,我只是将我的"mIsProcessingMessage"标志设置为 true,如下所示:

{
   QMutexLocker locker(&mIsProcessingMessageLock);
   mIsProcessingMessage = false;
};

也许这不是最好的解决方案,但它现在有效;)