QT Creator上位机学习(四)多线程操作

系列文章目录



前言

由于目前时间比较赶,同时还在学习FreeRTOS,可能没有很多时间详细学习Qt了,所以结合需要编写的上位机,先暂时跳过一些基础知识,挑一些重要的知识点先学会,其他的之后用到了再一边学一边补充吧。


多线程操作

为了防止某些操作消耗时间较长,导致其他程序无法响应,所以出现了多线程操作,需要处理好同步和数据交互。

多线程运行方式:
1.Qt的主线程是窗口线程:负责窗口事件的处理和窗口控件的更新
2.子线程(工作线程)负责后台的业务逻辑,不能对窗口对象操作
3.他们之间一般使用信号与槽完成数据的传递,当然也有一些其他的同步方式

一般Qt的多线程操作用的是QThread类。
线程之间同步:QMutex、QMutexLocker、QReadWritelock、QwaitCondition、Qsemaphore。
使用Qt Concurrent实现的多线程可以自动根据处理器内核个数调整线程个数,而且不用考虑对共享数据的保护问题。

多线程创建

网上搜索有很多的创建方式,我先总结一下利用QThread类的方式创建。

基本概念

一个QThread管理一个线程,一般我们自定义一个继承QThread的类,重定义虚函数run(),该函数里需要完成的线程任务。
一般在主线程创建线程,调用start()开始执行任务,其内部会自动调用run() ,开始任务循环执行。
在run() 函数里调用exit()或quit()结束线程,或在主线程调用terminate() 强制结束线程。

接口函数

//公共函数:
bool isFinished()     //线程是否结束
bool isRunning()      //线程是否运行
Priority priority()   //返回线程优先级
void setPriority(Priority priority)  //设置线程优先级
void exit(int returnCode=0)          //退出线程的事件循环,退出码为returnCode,0成功,否则出错
bool wait(unsigned long time)        //阻止线程执行,使之等待time毫秒(之后继续运行或者结束)

//公共槽函数
void quit()     //退出线程,返回代码0,等效exit(0)
void start(Priority priority)  //其内部调用run() 开始线程,操作系统根据priority调度
void terminate()            //终止线程运行,但不是立刻结束,而是等待操作系统结束,之后应该加上wait()

//信号
void finished()   //在线程结束时发射此信号
void start()    //在线程开始的时候执行,run()函数被调用之前发射此信号

//静态公共成员
int idealThreadCount()    //返回系统上能运行线程的理想个数
void msleep(unsigned long msecs)   //强制休眠msecs毫秒
void sleep(unsigned long secs)     //强制休眠secs秒
void usleep(unsigned long usecs)   //强制休眠usecs微秒

//保护函数
virtual void run()   //run() 被调用开始线程任务的执行,所以在run()里面实现线程的任务
int exec()            //有run()函数调用,进入线程的事件循环,等待exit()退出

线程类的定义实例

头文件实例:

#include  <Qthread>
class QDiceThread : public Qthread
{
	o_OBJECT
private :  //仅类内函数可以访问(继承也不行)
	int m_seq=0 ;//掷骰子次数序号
	int m_dicevalue;//骰子点数
	bool m_Paused=true;//暂停
	bool m_stop=false;//停止
protected:   //类内及继承可以访问
	void run() o_DECL_OVERRIDE;//线程任务,需要重定义
public:   //所有都能访问
	QDiceThread () ;
	void diceBegin () ; //掷一次骰子
	void dicePause () ;//暂停
	void stopThread ( ) ;//结束线程
signals :
	void newvalue(int seq,int dicevalue) ; //产生新点数
};

之后正常定义好线程的各部分函数,在主线程中启动等操作,或者控件中启动。

在窗口关闭时我们要确保所有的线程停止:

void Dialog : : closeEvent (QcloseEvent *event)
{ 
//窗口关闭事件,必须结束线程
if (threadA. isRunning())
{
	threadA.stopThread();
	threadA. wait();
}
	event->accept() ;  //关闭窗口,ignore()不关闭
}

重定义run():

void QDiceThread: : run()
{//线程任务
	m_stop=false;//启动线程时令m_stop=false
	m_seq=0 ; //掷骰子次数
	qsrand (Qtime::currentTime().msec());//随机数初始化,qsrand是线程安全的
	while (!m stop)//循环主体
	{
		if (!m_Paused)
		{
			m_dicevalue=qrand ( ); //获取随机数
			m_dicevalue=(m_dicevalue % 6)+1;
			m_seq++;
			emit newvalue(m_seq,m_dicevalue);//发射信号
			msleep (500) ; //线程休眠500ms
	} 
	quit( );//相当于exit (o),退出线程的事件循环
}

主要是通过信号与槽机制实现的,这里主线程会等待工作线程的信号通知,所以不涉及到线程之间变量同时读写的问题。

线程同步

如果不使用信号与槽机制,由于线程之间可能要同时访问一个变量,如果这个变量正在写入的时候读取,就会出现错误。因此出现了几种方法:

基础互斥量的线程同步

QMutex和QMutexLocker的类,创建互斥量,对它进行lock(),unlock(),tryLock(),在写入读出的时候,进行锁定,读写完成的时候解锁。
在这里插入图片描述
在这里插入图片描述

有些函数虽然涉及到变量的读写,但是如果只有一条语句,相当原子语句,不需要锁定保护

QMutexLocker简化了一些,接收一个互斥量进行构建并锁定,只有在其生命周期结束的时候才会解锁。

基于QReadWriteLock的线程同步

很明显,上面的方法,当同时有多个线程读取的时候,是不需要锁定的。
在这里插入图片描述

基于QWaitCondition的线程同步

前面为了避免同时访问资源时发生冲突。在一个线程解锁资源后,不能及时通知其他线程。

在这里插入图片描述

基于信号量的线程同步

在这里插入图片描述

总结

先简单了解一下,之后用到什么再补充吧

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值