Qt::BlockingQueuedConnection 与 QMetaCallEvent

Qt 创建连接类型如果是 Qt::BlockingQueuedConnection,即sender thread 与 receiver thread 不同,
但是要求 sender signal 与 receiver slot 执行是 不同线程间的同步行为。也即:在sender signal 发出后 sender线程 要 等待
receiver 线程的 slot 执行完后才能继续 向后执行指令。

该种方式sender与receiver的参数传递并未通过堆上内存的方式进行。而是receiver直接操作sender线程浅上的内存完成的。
因为sender线程处于同步等待状态,函数帧并未返回上一级函数调用者,因此sender的signal 函数桟帧数据处于有效状态。
又因为sender和receiver属于同一个进程,因此可以直接通过指针获取sender 线程调用栈中的内存数据。因此receiver slot执行完成后
在QMetaCallEvent对象销毁时 实质上 也没有释放堆内存的需求。而仅仅是通过父类析构函数执行了semaphore_.release() 通知
等待的sender线程 可以继续向后执行指令了。

实现方式:



  QSemaphore semaphore;
  {
      QMutexLocker locker(signalSlotLock(receiver));
      if (!c->isSingleShot && !c->receiver.loadAcquire())
          continue;
      QMetaCallEvent *ev = c->isSlotObject ?
          new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &**semaphore**) :
          new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
                             sender, signal_index, argv, &**semaphore**);
      QCoreApplication::postEvent(receiver, ev);
  }
  **semaphore.acquire();**

使用信号量在线程间进行同步,当QMetaCallEvent 在 receiver 线程EventLoop 处理完成后 会通过
void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type,
                                               QThreadData *data)
{
   ...........
   ...........
    **QScopedPointer**<QEvent> event_deleter(e); // will delete the event (with the mutex unlocked)

    
    QCoreApplication::sendEvent(r, e);  // after all that work, it's time to deliver the event.
    ...........
   ...........
}
posted @ 2024-09-18 18:10  MarsCactus  阅读(133)  评论(0编辑  收藏  举报