【问题标题】:Event synchronization between two threads in QtQt中两个线程之间的事件同步
【发布时间】:2012-06-29 09:31:32
【问题描述】:

我有两个线程,假设线程“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() 将为线程“A”中的recvCondition 启动。

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

QCoreApplication::postEvent(gpApp, pEvent);

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

QMutex mutex; 
       mutex.lock();

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

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

【问题讨论】:

  • 顺便说一句,你真的应该回到你之前的问题并接受最好的答案。否则,人们将根本不再理会您的问题,而您将来也不会得到任何答案。
  • 感谢 Johannes S. 的提示 ;)

标签: c++ qt thread-synchronization


【解决方案1】:

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

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

替代方案:

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 您仍然可以使用您的条件变量方法。我建议您阅读一些关于线程同步以及条件变量如何工作的内容。基本上,您需要“共享”一个互斥锁和一个条件变量。在发布事件之前锁定互斥锁并等待 CV(释放互斥锁)。在事件处理线程中获取mutex,处理事件,释放mutex,然后通知CV。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-01
    • 2018-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多