1

我有两个线程,假设线程“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析构函数被调用,因此wakeOne()将为recvConditionin 线程“A”启动。

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

QCoreApplication::postEvent(gpApp, pEvent);

<---- pEvent is already destroyed here ---->

QMutex mutex; 
       mutex.lock();

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

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

4

2 回答 2

1

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

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

选择:

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

于 2012-06-29T10:15:03.317 回答
1

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

我现在所做的是:我创建了一个在线程“A”和线程“B”之间使用的 QMutex 和布尔标志。

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;
};

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

于 2012-06-29T13:05:23.107 回答