QT中的线程
主线程(又称 GUI线程),负责监控窗口上的任何事件,一旦发现事件,立马处理.GUI线程只负责 UI刷新.
但是有时候,任务很耗时,GUI进程会卡住,UI无响应
这个时候创建一个新的子线程,负责处理 耗时的任务,注意:非GUI线程禁止访问 界面上任何元素. GUI线程只负责 UI刷新.
如果非要显示,子线程要传递数据给GUI,有GUI线程负责刷新.线程的创建:
C语言: pthread_create(thread_fun) thread_fun() {while(1){ }}
Qt提供了 QThread 类, 实现了线程功能,其中有一个方法 virtual void run() ;
就是线程执行体.子线程类myThread 继承自QThread: 实现一个QThread子类 myThread,重写run函数即可.
- new 子类对象
- start(); 线程已经执行run函数了.
互斥锁QMutex:
我们直到,线程间 可以共享内存,于是他们之间就可以通信.
但是 如果两个线程同时访问同一个资源,就会出现问题, 解决方法—加锁睡眠函数 静态方法QThread::msleep(int msec)
我们来了解一下互斥锁
互斥锁(同步)
在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,公司部门里,我在使用着打印机打印东西的同时(还没有打印完),别人刚好也在此刻使用打印机打印东西,如果不做任何处理的话,打印出来的东西肯定是错乱的。
在线程里也有这么一把锁——互斥锁(mutex),互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即上锁( lock )和解锁( unlock )。
【互斥锁的特点】:
- 原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;
- 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;
- 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。
【互斥锁的操作流程如下】:
- 在访问共享资源后临界区域前,对互斥锁进行加锁;
- 在访问完成后释放互斥锁导上的锁。在访问完成后释放互斥锁导上的锁;
- 对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。
下面是我们老师给的图解,非常的形象
线程的演示:
两个头文件
#ifndefTHREAD_H#defineTHREAD_H#include<QThread>#include<QMutex>structmsg{char temp;int himudity;int wind;char des[128];};
class senderThread:public QThread {
public:voidrun() override;senderThread(structmsg*p,QMutex *pMutex);senderThread(structmsg*p);~senderThread();
private:structmsg*pMsg;
QMutex *pmutex;};
class receiverThread :public QThread {
public:receiverThread(structmsg*p,QMutex *pMutex);receiverThread(structmsg*p);~receiverThread();voidrun() override;
private:structmsg*pMsg;
QMutex *pmutex;};#endif// THREAD_H
widget.h
#ifndefWIDGET_H#defineWIDGET_H#include<QWidget>#include"thread.h"#include<QMutex>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget;}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:Widget(QWidget *parent = nullptr);~Widget();
public slots:voidbtnClickedSlotFun();
private:
Ui::Widget *ui;structmsg*pMsg;
QMutex Mutex;
class senderThread *pSendThread;
class receiverThread *pRecvThread;};#endif// WIDGET_H
线程文件
#include"thread.h"#include<cstdio>#include<QDebug>void senderThread::run(){staticint cnt=0;while(1){
cnt++;
pmutex->lock();//使用之前加锁,注意 如果发现锁已经被锁上了, 则进程睡眠等待唤醒
pMsg->temp =(char)cnt;
QThread::msleep(1000);
pMsg->himudity=cnt*11;
QThread::msleep(1000);
pMsg->wind = cnt+100;
QThread::msleep(1000);snprintf(pMsg->des,sizeof(pMsg->des),"sunday,tmp=%d hm=%d win=%d.",pMsg->temp,pMsg->himudity,pMsg->wind);
pmutex->unlock();//使用之后解锁, 也会唤醒其他等待的进程}}
senderThread::senderThread(msg *p, QMutex *pMutex){
pMsg=p;
pmutex = pMutex;}
senderThread::senderThread(msg *p){
pMsg=p;}
senderThread::~senderThread(){}
receiverThread::receiverThread(msg *p, QMutex *pMutex){
pMsg=p;
pmutex = pMutex;}
receiverThread::receiverThread(msg *p){
pMsg=p;}
receiverThread::~receiverThread(){}void receiverThread::run(){while(1){
pmutex->lock();qDebug()<<"tmp:"<<int(pMsg->temp)<<" hm:"<<pMsg->himudity<<" win="<<pMsg->wind<<" des:"<<pMsg->des;
pmutex->unlock();
QThread::sleep(1);}}
widget.cpp
#include"widget.h"#include"ui_widget.h"
Widget::Widget(QWidget *parent):QWidget(parent),ui(new Ui::Widget){
ui->setupUi(this);//创建两个线程共享的空间
pMsg = new structmsg;memset(pMsg,0,sizeof(structmsg));
pSendThread = new senderThread(pMsg,&Mutex);
pRecvThread = new receiverThread(pMsg,&Mutex);
pSendThread->start();
pRecvThread->start();connect(ui->btntest,SIGNAL(clicked()),this,SLOT(btnClickedSlotFun()));}
Widget::~Widget(){
delete ui;
delete pMsg;}void Widget::btnClickedSlotFun(){
QString str =QString("temp=%1 hm=%2 wind=%3 des:%4").arg(int(pMsg->temp)).arg(pMsg->himudity).arg(pMsg->wind).arg(pMsg->des);
ui->textEdit->setText(str);}
运行后我们得到的是这个效果:
在加锁以后我们写入的数据就不会被覆盖掉,就可以得到我们需要的数据了
版权归原作者 小镇春风 所有, 如有侵权,请联系我们删除。