令人不解的问题:

当槽函数是线程类的成员时,为什么依然不在本线程内被调用执行?

隐藏的问题:对象依附于哪一个线程?对象的依附性与槽函数执行的关系?对象的依附性是否可以改变?

对象依附于哪个线程?默认情况下,对象依附于自身被创建的线程例如:对象在主线程(main()函数)中被创建,则依附于主线程

int main(int argc, char* argv[])
{//...TestThread t;     //依附于主线程MyObject m;       //依附于主线程
}

对象的依附性与槽函数执行的关系?默认情况下,槽函数在其所依附的线程中被调用执行

int main(int argc, char* argv[])
{//...TestThread t;     //依附于主线程MyObject m;       //依附于主线程//下面连接中的槽函数都在主线程中被调用执行QObject::connect(&t,SIGNAL(started()),&m,SLOT(getStarted()));QObject::connect(&t,SIGNAL(testSignal()),&m,SLOT(testSlot()));
}

对象的依附性是否可以改变?QObject::moveToThread用于改变对象的线程的依附性,使得对象的槽函数在依附的线程中被调用执行

int main(int argc, char* argv[])
{//...TestThread t;     //依附于主线程MyObject m;       //依附于主线程//改变对象m的线程的依附性,使其依附于线程tm.moveToThread(&t)
}

对象的依附性

MyObject.h

#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>class MyObject : public QObject
{Q_OBJECT
public:MyObject();
protected slots:void getStarted();void testSlot();
};#endif // MYOBJECT_H

View Code

TestThread.h

#ifndef TESTTHREAD_H
#define TESTTHREAD_H#include <QThread>class TestThread : public QThread
{Q_OBJECT
protected:void run();
public:TestThread();signals:void testSignal();
protected slots:void testSlot();
};#endif // TESTTHREAD_H

View Code

MyObject.cpp

#include "MyObject.h"
#include <QObject>
#include <QThread>
#include <QDebug>MyObject::MyObject()
{}void MyObject::getStarted()
{qDebug() <<"void MyObject::getStarted()tid = " << QThread::currentThreadId() ;
}void MyObject::testSlot()
{qDebug() << "void MyObject::testSlot() " << QThread::currentThreadId() ;
}

View Code

TestThread.cpp

#include "TestThread.h"
#include <QDebug>TestThread::TestThread()
{connect(this,SIGNAL(testSignal()),this,SLOT(testSlot()));
}void TestThread::run()
{qDebug() << "void TestThread::run() begin...tid = " << currentThreadId();for(int i=0; i<10; i++){qDebug() << "void TestThread::run() i = " << i;sleep(1);}emit testSignal(); //发射的信号谁来接收呢,可以在构造函数中将信号和槽函数进行关联。qDebug() << "void TestThread::run() end...";
}void TestThread::testSlot()
{qDebug() << "void TestThread::testSlot() tid = " << currentThreadId();
}

View Code

main.cpp

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include "TestThread.h"
#include "MyObject.h"int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "main tid() " << QThread::currentThreadId();TestThread t;MyObject m;QObject::connect(&t,SIGNAL(started()),&m,SLOT(getStarted()));QObject::connect(&t,SIGNAL(testSignal()),&m,SLOT(testSlot()));m.moveToThread(&t);t.start();return a.exec();
}

View Code

课程中使用的是Qt4,MyObject相关的槽函数没有被调用,但是使用Qt5.4,MyObject相关的槽函数被调用了。

下面分析没有被调用的情况:

问题:实验中对象m的槽函数为什么没有全部被执行?

线程中的事件循环信号与槽的机制需要事件循环的支持QThread类中提供的exec()函数用于开启线程的事件循环只有开启事件循环,槽函数才能在信号发送后被调用

信号的发送是随时随地都可以完成的,发送完成后,信号就到事件队列中去了。信号进入事件队列中去有什么用呢?没人理它,它什么用都没有。如何处理事件队列呢?此时事件循环就派上用场了。但凡通过exec开启了事件循环,就会不停的从事件队列中取信号,取到信号后就会去判断该信号有没有关联相关的槽函数,如果有对应的槽函数,则调用相应的槽函数。

想要槽函数在指定的线程中被调用,需要在指定的线程中调用exec函数,开启事件循环。小结论:前提条件对象依附的线程开启了事件循环后置结果对象中的槽函数在依附的线程中被调用执行

只需要在TestThread.cpp的run函数中加上exec函数即可

void TestThread::run()
{qDebug() << "void TestThread::run() begin...tid = " << currentThreadId();for(int i=0; i<10; i++){qDebug() << "void TestThread::run() i = " << i;sleep(1);}emit testSignal(); //发射的信号谁来接收呢,可以在构造函数中将信号和槽函数进行关联。exec();qDebug() << "void TestThread::run() end...";
}

View Code

从打印结果看,与上面没有使用exec的执行结果并无不同,很可能是因为版本不同造成的。

从打印结果看,MyObject的两个槽函数都被调用了,且是在依附于t的那个线程。但是t的槽函数还是依附于主线程,我也想让t的槽函数依附t,怎么操作?非常简单,只需要在main.cpp中的main函数中,加入t.moveToThread(&t)即可,如下所示:

int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "main tid() " << QThread::currentThreadId();TestThread t;MyObject m;QObject::connect(&t,SIGNAL(started()),&m,SLOT(getStarted()));QObject::connect(&t,SIGNAL(testSignal()),&m,SLOT(testSlot()));m.moveToThread(&t);t.moveToThread(&t);t.start();return a.exec();
}

View Code

研究槽函数的具体执行线程有什么意义?当信号的发送与对应槽函数的执行在不同线程中,可能产生临界资源的竞争问题

比如说,在run函数对某一个临界资源进行修改,在槽函数中也对临界资源进行修改,槽函数的调用是在另一个线程中完成的,此时调用槽函数的线程和本身的线程就可能产生竞争问题。

多线程中的信号与槽(中)相关推荐

  1. Qt多线程中的信号与槽

    文章目录 1 多线程中的信号与槽 2 对象的依附性 2.1 对象的依附性 2.2 开启线程事件循环 2.3 线程事件循环的结束 2.4 设计实例 3 信号与槽的连接方式 3.1 Qt::DirectC ...

  2. Qt 多线程中地信号与槽

    Qt 多线程中地信号与槽 函数原型: 1 QObject::connect(const QObject *sender, const char *signal, const QObject *rece ...

  3. Qt静态函数中的信号和槽问题

    目录 介绍 Qt中的信号和槽 一般形式 当发送信号的地方为静态函数时 存在问题 解决方案 介绍 信号和插槽用于对象之间的通信.信号和插槽机制是Qt的一个核心特性,可能是与其他框架提供的特性最为不同的部 ...

  4. Qt编程中的信号和槽机制

    Qt编程中的信号和槽机制 在使用自定义类创建一个按钮之后,只能看到一个按钮的图形,但是使用鼠标点击并无任何反应,下面想要实现一个"点击按钮可以关闭窗口"的功能. 关闭窗口的功能可以 ...

  5. Qt中的信号与槽机制解析

    注:要想使用Qt的核心机制信号与槽,就必须在类的私有数据区声明Q_OBJECT宏,然后会有moc编译器负责读取这个宏进行代码转化,从而使Qt这个特有的机制得到使用. 所谓信号槽,简单来说,就像是插销一 ...

  6. Qt多线程使用 和 信号与槽传参 需要注意的问题

    Qt中提供了线程类,默认窗口是主线程,这个时候如果我们的业务逻辑很费时,就会一直使用主线程,页面可能会卡顿甚至崩溃.那么将业务逻辑放入子线程,能够避免页面的卡顿,保证操作是流畅的,还能提高程序的执行效 ...

  7. python qt designer 重定向_[Python自学] PyQT5-QTDesigner中关联信号和槽

    一.什么是信号什么是槽 信号和槽是QT的核心机制. 1.信号 信号,是由对象或空间发出去的消息.例如单击按钮控件. 信号可以理解为触发的事件. 2.槽 发送出去的信号需要有一段代码来拦截,并执行一些操 ...

  8. matlab有信号与槽机制么,笔记:Qt5中的信号与槽,不要再用SIGNAL,SLOT了

    看的书是Qt5.9,但书上却用的Qt4中的通用用法:SIGNAL和SLOT宏, 不过,书后面却又给了一种传递信号和槽函数地址的用法(Qt5的用法),但是这本书的作者在这块却说的不好,如下图: 首先要知 ...

  9. Qt中解决信号和槽不能使用自定义结构体的问题

    在Qt中信号和槽使用自定义的结构时,运行的时候发现报错不能识别结构体 解决办法: 一定要将自定义结构体定义为typedef struct 使用Q_DECLARE_METATYPE(结构体名),将结构体 ...

最新文章

  1. codeforces 贪心+优先队列_贪心(贪婪),在你们家乡话中怎么说·
  2. python是c语言写的吗-先学C语言还是Python?资深程序员往往是这样建议的!
  3. java异步调用第三方接口_Java调用第三方系统接口获取数据
  4. 在继承中派生类成员的访问权限测试
  5. DHL全球货运与第四范式达成合作
  6. 缩小窗口时CSS背景图出现右侧空白BUG的解决方法
  7. android日志打印机制,Android4_使用Log打印
  8. go 链路追踪_使用opentracing,jaeger实现golang链路追踪
  9. saefetchurl java_新浪云sae给的图片操作类
  10. js检测是否安装java_js判断当前浏览器是否是源生app的webview
  11. 面向对象的数据库db4o: 安装并使用db4o
  12. Java设计模式--单例模式(代码详解懒汉、饿汉模式)
  13. vue导出word文档
  14. Volatility3安装
  15. html 淡入淡出效果,css3 transition实现淡入淡出效果 - 小俊学习网
  16. unity 打安卓包 华为手机图片被压扁
  17. 可以像微信钱包一样?2020年数字钱包技术重要的进化方向(上)
  18. Flutter 自定义Widget——风车实现
  19. (资源)百度云盘:驴火歌王:阅读真的很难提分第2讲:洞茶 (2013北京中考)
  20. Vue学习第36天——PC端和移动端常用的Vue UI组件库

热门文章

  1. java服务端微信商户企业付款提现到个人银行卡实现
  2. 王者荣耀微信有个服务器叫洛神降临,王者荣耀之洛神降临,覆水难收,洛神
  3. 三星android文件传输,微软“你的手机”应用现已支持三星手机投屏后与PC之间拖拽传输文件...
  4. 大四考研没上岸怎么快速获得大厂offer呢?
  5. vscode官方下载太慢解决办法
  6. 基于at91sam9260芯片在u-boot写添加看门狗控制命令
  7. android显示二维毫秒,Android应用开发Android 悬浮窗显示毫秒级时间
  8. ContextCapture系列教程(四):新建工程、添加照片、相机参数设置、选择坐标系统
  9. 骁龙8 gen1和骁龙870哪个好
  10. 若依(ruoyi)redis配置详解