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

时间:2012-06-29 09:31:33

标签: c++ qt thread-synchronization

我有两个线程,让我们说线程“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”中的wakeOne()启动recvCondition

一切似乎都很好,这只是一件事! 看起来有时 ~IPCMessageEvent 会在预期之后被调用...

QCoreApplication::postEvent(gpApp, pEvent);

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

QMutex mutex; 
       mutex.lock();

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

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

2 个答案:

答案 0 :(得分:1)

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

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

<强>替代:

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

答案 1 :(得分:1)

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

我现在做的是: 我创建了一个QMutex和boolean标志,用于线程“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;
};

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