- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent)
- {
- pThreadCon = new CSerialThread();
- pThreadCon->start();
- m_pTimer = new QTimer();
- connect(m_pTimer,SIGNAL(timeout()),SLOT(onTimer()));
- m_pTimer->start(1000);
- }
- void MainWindow::onTimer()
- {
- m_pTimer->stop();
- connect(this,SIGNAL(onSignal()),g_pThread,SLOT(onTimer()),Qt::QueuedConnection);
- emit onSignal();
- this->disconnect();
- }
- void CSerialThread::run()
- {
- g_pThread = new CThread();
- }
- CThread::CThread(QObject *parent) :
- QThread(parent)
- {
- }
- void CThread::onTimer()
- {
- sleep(5);
- qDebug("------onTimer call");
- }
只添加了部分代码, 运行这个程序是看不到打印信息的, 说明这个信号没有接收到, 如果将 connect 最后一个参数改成直接连接, 会有打印, 但是主界面会卡住 5 秒. 一直被这个问题困扰, 为什么 g_pThread 收不到信号呢, 首先应该知道, Qt 的信号和槽是基于事件循环的, 就像 main 函数最后都会有一句 return exec(); 这里就启动了事件循环, 除了信号触发线程与接收者线程相同的情况能直接调用到 slot, 其它情况都依赖事件机制. QThread::run() 实际上是简单调用了 QThread::exec(), 而它启动了线程的事件循环, 但是 run() 函数结束后, 事件循环结束了, 这个时候我们再发送信号, 没有事件循环的支持, g_pThread 就收不到信号了.
QThread 的内部结构非常有趣:
QThread 并不生存于执行 run() 的新线程内. 它生存于旧线程中.
QThread 的大多数成员方法是线程的控制接口, 并设计成从旧线程中被调用. 不要使用 moveToThread() 将该接口移动到新创建的线程中; 调用 moveToThread(this) 被视为不好的实践.
exec() 和静态方法 usleep(),msleep(),sleep() 要在新创建的线程中调用.
QThread 子类中定义的其他成员可在两个线程中访问. 开发人员负责访问的控制. 一个典型的策略是在 start() 被调用前设置成员变量. 一旦工作线程开始运行, 主线程不应该操作其他成员. 当工作线程终止后, 主线程可以再次访问其他成员. 这是一个在线程开始前传递参数并在结束后收集结果的便捷的策略.
QObject 必须始终和 parent 在同一个线程.
所以解决上面代码收不到信号的问题其实很简单, 在线程的 run(); 函数中添加一个事件循环就可以了, 即加入一句 exec();
来源: http://www.bubuko.com/infodetail-2746350.html