qt多线程有2种方式

1.继承QThread的多线程

线程创建  :

QThread只有run函数是在新线程里的,但一般调用start函数后,会自动调用run函数,从而使线程起来。run()为虚函数。

如果线程已经运行,你重复调用start其实是不会进行任何处理,所以建议在start之前进行判断:使用isRunning函数。

线程退出:

在run函数调用exit()或者quit()函数可以结束线程,或在主线程调用terminate强制结束线程。

在线程运行过程调用quit、exit函数有什么效果
答案是:不会发生任何效果,QThread不会因为你调用quit或exit函数而退出正在运行到一半的run。最简单的方法是添加一个bool变量,通过主线程修改这个bool变量来进行终止,但这样有可能引起访问冲突,需要加锁。

QMutex m_lock;
QMutexLocker locker(&m_lock);
m_isCanRun = false;

常用的函数

1.void setPriority(Priority priority);

2.Priority priority() const;

3.bool isFinished() const;

4.bool isRunning() const;

5.void exit(int retcode = 0);

6.void quit();   相当于exit(0)

7.bool wait(unsigned long time = ULONG_MAX);    //线程退出过程,需要调用wait()来阻塞等待,

8.void terminate();//使用terminate之后应该使用wait

9.void start(Priority = InheritPriority);

10.virtual void run();

11.static void sleep(unsigned long);

12.void deleteLater();

Q_SIGNALS:
void started(QPrivateSignal);    //开始前发射
void finished(QPrivateSignal);  //结束时发射该信号
注意:
1.使用new QThread 的方式创建线程,可以使用信号finished,槽deleteLater,自动销毁分配的内存。即connect(m_printThread,&QPrintThread::finished,m_printThread,&QObject::deleteLater);2. finished和destroyed,个人认为destroyed是在finished之后发生的。所以在new QThread 的方式,线程对象虽然销毁,但指针没有置null,要使用finished信号,自定义槽函数实现线程对象置null.即connect(m_pSaveThread,&SaveDataThread::destroyed,this,&MainWindow::SaveDataThreadDestroy)

另外在线程中,也可以自定义信号,从而与主线程通信。

全局线程:

创建:

//全局线程创建时可以把窗体指针作为父对象

m_thread = new ThreadFromQThread(this);

m_thread->start();

退出:

m_thread->stopImmediately();

m_thread->wait();  //这一句是主线程等待子线程结束才能继续往下执行.(m_thread的父类是主线程窗口,主线程窗口如果没等子线程结束就destroy的话,会顺手把m_threaddelete这时就会奔溃了),因此wait的作用就是挂起,一直等到子线程结束

bool QThread::wait ( unsigned long time = ULONG_MAX ):这个函数阻塞线程直到满足下面的条件之一
1.与这个线程对象关联的线程已经结束执行(例如从run函数返回)。如果线程结束返回真值。如果线程还没有开始也返回真值
2.到达定时结束时刻。如果定时是ULONG_MAX (默认值),线程就会一直等下去(线程必须从run函数返回)。时间到,函数返回假值

局部线程:

创建:

m_printThread = new QPrintThread(NULL);//局部线程,没有父对象
m_printThread->start();

退出:

m_printThread->stopImmediately();

connect(m_printThread,&QPrintThread::finished,m_printThread,&QObject::deleteLater);//自动销毁分配的内存

connect(m_pSaveThread,&SaveDataThread::destroyed,this,&MainWindow::SaveDataThreadDestroy);  //SaveDataThreadDestroy自定义的槽函数

用一个临时变量记录当前正在运行的局部线程,由于线程结束时会销毁自己,因此要通知主线程把这个保存线程指针的临时变量设置为NULL
因此用到了QObject::destroyed信号,在线程对象析构时通知UI把m_printThread 设置为nullptr;

void MainWindow::SaveDataThreadDestroy(QObject *obj)
{  if(qobject_cast<QObject*>(m_pSaveThread) == obj )   {      m_pSaveThread = NULL;   }
}

2.继承QObject的多线程

用QObject来实现多线程有个非常好的优点,就是默认就支持事件循环(Qt的许多非GUI类也需要事件循环支持,如QTimer、QTcpSocket),QThread要支持事件循环需要在QThread::run()中调用QThread::exec()来提供对消息循环的支持,否则那些需要事件循环支持的类都不能正常发送信号,因此如果要使用信号和槽,那就直接使用QObject来实现多线程。

使用QObject来实现多线程比用继承QThread的方法更加灵活,整个类都是在新的线程中,通过信号槽和主线程传递数据

全局线程:

m_pGetDataThread = new QThread();
m_pGetDataThreadObj = new DataThreadObject();
m_pGetDataThreadObj->moveToThread(m_pGetDataThread);
m_pGetDataThread->start();

退出

connect(m_pGetDataThread,&QThread::finished,m_pGetDataThread,&QObject::deleteLater);//看情况

connect(m_pGetDataThread,&QThread::finished,m_pGetDataThreadObj,&QObject::deleteLater);//这个函数必须使用,不然会内存泄漏

MainWindow::~MainWindow()
{  if(m_pGetDataThread)   {      m_pGetDataThread->quit();    }
}

//m_pGetDataThread 因为是通过new出来的,即在堆内创建,所以可以通过deleteLater让线程自杀。如果是直接实例化的,需要在析构时就需要调用QThread::wait(),而不是connect(m_pGetDataThread,&QThread::finished,m_pGetDataThread,&QObject::deleteLater);

connect(m_pGetDataThread,&QThread::finished,m_pGetDataThreadObj,&QObject::deleteLater);//这个函数必须使用,不然会内存泄漏

m_pGetDataThread->quit();

m_pGetDataThread->wait();

//

1.善用QObject::deleteLater 和 QObject::destroyed来进行内存管理 
由于多线程环境你不可预料下一步是哪个语句执行,因此,加锁和自动删除是很有用的工具,加锁是通过效率换取安全,用Qt的信号槽系统可以更有效的处理这些问题。

2.如果线程要用到消息循环,使用继承QObject的多线程方法更简单
继承QObject的多线程不能指定父对象
把所有耗时操作都作为槽函数
QMutex会带来一定的耗时,大概速度会降低1.5倍(Release模式)

3.子对象不能脱离父对象,单独切换到与父对象不同的线程中

4. QObject的子对象必须在创建其parent的线程中创建

5.在Qt中,当一个对象被移到另一个线程时,他的所有子对象也会一并转移到另外那个线程。

6.在qt中 线程创建的对象必须在线程中释放。

7.在qt中 io类不能跨线程调用Qobject。可通过信号槽的方式

线程同步问题  跟linux的思想一模一样,只是函数名不同而已。

1.QMutex

2.QMutexLocker    是对QMutex的简化,直接使用构造函数和析构函数的方式,而不是lock和unlock的调用

3. QReadWriteLock 读写锁,可以多个线程以只读方式访问,但只有一个线程以写的方式访问。

LockForRead();

LockForWrite();

unlock();

另外,QReadlocker 和QWriteLocker是QReadWriteLock的简化,如同QMutexLocker  是QMutex   的简化一样。无须使用unlock().

4. QWaitCondition

bool wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX);  //解锁互斥量,并阻塞等待唤醒,唤醒后由锁定互斥量
bool wait(QReadWriteLock *lockedReadWriteLock, unsigned long time = ULONG_MAX);
void wakeOne(); //唤醒一个等待线程,具体哪一个线程,由操作系统决定
void wakeAll();//唤醒所有等待线程

5. QSemaphore 信号量    比互斥量更高级,互斥量只能锁定一次,信号量可以多次使用,每次创建时可以设定初始值 void acquire(int n = 1);  //获取n个资源

bool tryAcquire(int n = 1);

bool tryAcquire(int n, int timeout);

void release(int n = 1);  //释放资源

参考:

1.https://blog.csdn.net/czyt1988/article/details/71194457

2.https://www.cnblogs.com/andreitang/archive/2011/08/25/2128508.html

qt 两种不同方式的多线程相关推荐

  1. Java多线程两种实现方式的对比

    Java多线程两种实现方式的对比 一种,直接继承Thread类 一种,实现Thread类的Runnable接口 两种方式的区别 比如,售票厅有四个窗口,可以发售某日某次列出的100张车票,此时,100 ...

  2. 多线程python实现方式_python多线程的两种实现方式(代码教程)

    本篇文章给大家带来的内容是关于python多线程的两种实现方式(代码教程),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 线程是轻量级的进程,进程中可划分出多个线程,线程可独立的调度 ...

  3. java 同步方式 lock_java的两种同步方式, Synchronized与ReentrantLock的区别

    java在编写多线程程序时,为了保证线程安全,需要对数据同步,经常用到两种同步方式就是Synchronized和重入锁ReentrantLock. 相似点: 这两种同步方式有很多相似之处,它们都是加锁 ...

  4. 1000个苹果要分到10个箱子中去 两种分析方式

    前些日子接到了一个Java开发的电话面试,接了电话人家开门见山就直接说现在是否方便,什么什么时候收到您的简历投递,是否可以进行电话面试,如果可以就可以直接开始了,emmm,这么突然,也没好意思问公司名 ...

  5. 【无标题】单例模式的两种创建方式:饿汉式和懒汉式

    这里写自定义目录标题 单例模式的两种创建方式:饿汉式和懒汉式 欢迎使用Markdown编辑器 新的改变 功能快捷键 合理的创建标题,有助于目录的生成 如何改变文本的样式 插入链接与图片 如何插入一段漂 ...

  6. PyQt5随笔:Qtdesigner设计转换而来的界面.py文件两种调用方式

    PyQt5随笔:Qtdesigner设计转换而来的界面.py文件两种调用方式 文章目录 PyQt5随笔:Qtdesigner设计转换而来的界面.py文件两种调用方式 1.前言 2.方式一:另建 py ...

  7. 【Django】项目中调用深度学习模型model.predict()(Django两种启动方式runserver和uwsgi的区别)

    目录 问题 测试 解决方法 Django两种启动方式runserver和uwsgi的区别 问题 部署含有深度学习模型的Django项目的uWSGI.Nginx服务器的时候,所有模块都可以正常运行,也可 ...

  8. Android service的两种使用方式bindService和startService使用方式

    服务与多线程的区别: 服务仍然是运行在主线程中,而Thread则是真正的开启了一个新的线程来执行先关操作. 那为什么要用服务呢,初步理解是服务是为了更好地管理线程.试想,当我们在某一个activity ...

  9. C++中的两种绑定方式(静态绑定、动态绑定)

    两种绑定方式 静态绑定:在编译时刻,根据指针或引用变量的静态类型来决定成员函数属于哪一个类. 动态绑定:在运行时刻,根据指针或引用变量实际指向或引用的对象类型(动态类型)来确定成员函数属于哪一个类. ...

  10. (C++)string 的两种输入方式和输出方式

    注:头文件如下 #include<string> #include<cstdio> #include<iostream>using namespace std; 注 ...

最新文章

  1. 苹果被罚3.1635亿元,因不愿开放第三方支付!
  2. 基于VMware vSphere 5.0的服务器虚拟化实践(8)
  3. 基于Pytorch再次解读ResNet现代卷积神经网络
  4. Fabric--简单的资产Chaincode
  5. java继承构造_Java语言的继承结构
  6. php 的常量能不能删除,php能删除常量吗
  7. 2020年CNCF和开源项目开发速度
  8. kubectl apply -f_新车 | 新款捷豹F-PACE登陆广州车展!内外提升十分明显
  9. 《Reids 设计与实现》第十七章 发布与订阅
  10. Hadoop hdfs编程案例和java交互
  11. 网页围棋对战闪亮登场(Flex+java)
  12. [OMNET++]ALOHA协议
  13. MongoDB LBS经纬度查询操作
  14. js-----词法分析过程
  15. notebook常用快捷键
  16. Springboot文件上传报错:failed to convert java.lang.String to org.springframework.util.unit.DataSize
  17. 【JVM】JVM系列
  18. 树莓派应用之“魔镜”
  19. 公司员工阳了怎么办?
  20. 【47.40%】【BZOJ 1875】[SDOI2009]HH去散步

热门文章

  1. linux 命令行 光标移动技巧
  2. 微信客户端抽奖转盘效果
  3. Android开发者指南-用户界面-拖放-Drag and Drop[原创译文]
  4. php自己遇到的一些问题
  5. GreenDao的学习和使用
  6. php练手的项目,learnphp.beginmaker.com
  7. 如何找一个程序员做男朋友?
  8. 专题二:MATLAB矩阵处理
  9. MAC编译lame ld: symbol(s) not found for architecture x86_64/_lame_init_old“, referenced from
  10. configure: error: udev support requested but libudev header not installed