QT多线程中,对象信号与槽连接不上的问题
2016-07-04 11:06
731 查看
连接不上的问题有很多种,如信号与槽的参数不匹配,参数为自定义类型等等。今天碰到的一个问题是多线程中,信号与槽一直连接不上。防止忘记,记录一下。
这个问题的情景是一个QObject的派生类不是在主线程里面创建的,然后这个派生类用默认的连接方式去连接信号,这时是连接不上的。
问题的根源就在于,异步连接的时候,这个信号是由接收者所在的线程的事件处理机制来处理的,如果接收者所在的线程没有事件处理的话,这个信号就不会被处理。看看代码:
voidQCoreApplication::postEvent(QObject*receiver,QEvent*event,
int priority)
{
if (receiver == 0) {
qWarning("QCoreApplication::postEvent: Unexpected null receiver");
delete
event;
return;
}
QThreadData*
volatile *pdata= &receiver->d_func()->threadData;
QThreadData*data = *pdata;
if (!data) {
// postingduring destruction? just delete the event to prevent a leak
delete
event;
return;
}
// lock the postevent mutex
data->postEventList.mutex.lock();
// if object hasmoved to another thread, follow it
while (data != *pdata) {
data->postEventList.mutex.unlock();
data =*pdata;
if (!data) {
//posting during destruction? just delete the event to prevent a leak
deleteevent;
return;
}
data->postEventList.mutex.lock();
}
QMutexUnlockerlocker(&data->postEventList.mutex);
// if this is oneof the compressible events, do compression
if (receiver->d_func()->postedEvents
&&
self&& self->compressEvent(event,receiver,&data->postEventList)){
return;
}
if (event->type() ==QEvent::DeferredDelete&&data
== QThreadData::current()) {
// rememberthe current running eventloop for DeferredDelete
// eventsposted in the receiver's thread
static_cast<QDeferredDeleteEvent *>(event)->level
=data->loopLevel;
}
// delete theevent on exceptions to protect against memory leaks till the event is
// properly ownedin the postEventList
QScopedPointer<QEvent>eventDeleter(event);
data->postEventList.addEvent(QPostEvent(receiver,event,
priority));
eventDeleter.take();
event->posted =true;
++receiver->d_func()->postedEvents;
data->canWait =false;
locker.unlock();
QAbstractEventDispatcher*dispatcher =data->eventDispatcher.loadAcquire();
if (dispatcher)
dispatcher->wakeUp();
}
从上面可以看出,信号被包装成一个事件加到了接收者所在的线程的事件队列当中去了。
暂时想到的几种解决方法:
在接收者创建线程中,把接收者移动到主线程中:
pReceiverObj->moveToThread(QApplication::instance()->thread());
这样发送信号的时候,就会在主线程事件队列处理中来处理了。
把connect的最后一个参数改成Qt::DirectConnection,使用直连接的方式来连接信号与槽。
启动QThread自己的事件队列处理(exec())。
如果有什么错误和问题,请各位多多指教。
连接不上的问题有很多种,如信号与槽的参数不匹配,参数为自定义类型等等。今天碰到的一个问题是多线程中,信号与槽一直连接不上。防止忘记,记录一下。
这个问题的情景是一个QObject的派生类不是在主线程里面创建的,然后这个派生类用默认的连接方式去连接信号,这时是连接不上的。
问题的根源就在于,异步连接的时候,这个信号是由接收者所在的线程的事件处理机制来处理的,如果接收者所在的线程没有事件处理的话,这个信号就不会被处理。看看代码:
voidQCoreApplication::postEvent(QObject*receiver,QEvent*event,
int priority)
{
if (receiver == 0) {
qWarning("QCoreApplication::postEvent: Unexpected null receiver");
delete
event;
return;
}
QThreadData*
volatile *pdata= &receiver->d_func()->threadData;
QThreadData*data = *pdata;
if (!data) {
// postingduring destruction? just delete the event to prevent a leak
delete
event;
return;
}
// lock the postevent mutex
data->postEventList.mutex.lock();
// if object hasmoved to another thread, follow it
while (data != *pdata) {
data->postEventList.mutex.unlock();
data =*pdata;
if (!data) {
//posting during destruction? just delete the event to prevent a leak
deleteevent;
return;
}
data->postEventList.mutex.lock();
}
QMutexUnlockerlocker(&data->postEventList.mutex);
// if this is oneof the compressible events, do compression
if (receiver->d_func()->postedEvents
&&
self&& self->compressEvent(event,receiver,&data->postEventList)){
return;
}
if (event->type() ==QEvent::DeferredDelete&&data
== QThreadData::current()) {
// rememberthe current running eventloop for DeferredDelete
// eventsposted in the receiver's thread
static_cast<QDeferredDeleteEvent *>(event)->level
=data->loopLevel;
}
// delete theevent on exceptions to protect against memory leaks till the event is
// properly ownedin the postEventList
QScopedPointer<QEvent>eventDeleter(event);
data->postEventList.addEvent(QPostEvent(receiver,event,
priority));
eventDeleter.take();
event->posted =true;
++receiver->d_func()->postedEvents;
data->canWait =false;
locker.unlock();
QAbstractEventDispatcher*dispatcher =data->eventDispatcher.loadAcquire();
if (dispatcher)
dispatcher->wakeUp();
}
从上面可以看出,信号被包装成一个事件加到了接收者所在的线程的事件队列当中去了。
暂时想到的几种解决方法:
在接收者创建线程中,把接收者移动到主线程中:
pReceiverObj->moveToThread(QApplication::instance()->thread());
这样发送信号的时候,就会在主线程事件队列处理中来处理了。
把connect的最后一个参数改成Qt::DirectConnection,使用直连接的方式来连接信号与槽。
启动QThread自己的事件队列处理(exec())。
如果有什么错误和问题,请各位多多指教。
相关文章推荐
- qt 预言家 翻译
- qt 打印 刻度尺 曲线 复杂图像
- MQTT协议
- XMPP协议、MQTT协议、HTTP协议、CoAP协议的基本比较
- QT图片资源加载的方式(转载)
- QT 默认环境路径配置方法
- Qt之国际化
- 嵌入式QT软键盘
- win7上qt5.1.1 opencv2.4.7 cmake2.8.12.1环境搭建(关键在环境变量)
- QTabWidget标签实现双击关闭(转)
- Qt中添加OpenCV库
- QT自制类分享 一图流按钮
- pyqt 加载资源文件
- 配置pyqt4开发环境, 之 Pycharm配置
- QT串口通信(1)
- 自动化测试.工具
- PyQt界面编程应用与实践
- ubuntu16.04 安装完Qt后,编译项目出现cannot find -lGL
- QT 文件拖放事件dropEvent和dragEnterEvent
- UFT开发实例:QTP调用OutLook自动发送邮件