赞
踩
主线程(又称 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资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。
【互斥锁的操作流程如下】:
在访问共享资源后临界区域前,对互斥锁进行加锁;
在访问完成后释放互斥锁导上的锁。在访问完成后释放互斥锁导上的锁;
对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。
下面是我们老师给的图解,非常的形象
#ifndef THREAD_H #define THREAD_H #include <QThread> #include <QMutex> struct msg { char temp; int himudity; int wind; char des[128]; }; class senderThread:public QThread { public: void run() override; senderThread(struct msg *p,QMutex *pMutex); senderThread(struct msg *p); ~senderThread(); private: struct msg *pMsg; QMutex *pmutex; }; class receiverThread :public QThread { public: receiverThread(struct msg*p,QMutex *pMutex); receiverThread(struct msg *p); ~receiverThread(); void run() override; private: struct msg *pMsg; QMutex *pmutex; }; #endif // THREAD_H
widget.h
#ifndef WIDGET_H #define WIDGET_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: void btnClickedSlotFun(); private: Ui::Widget *ui; struct msg *pMsg; QMutex Mutex; class senderThread *pSendThread; class receiverThread *pRecvThread; }; #endif // WIDGET_H
线程文件
#include "thread.h" #include <cstdio> #include <QDebug> void senderThread::run() { static int 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 struct msg; memset(pMsg,0,sizeof(struct msg)); 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); }
运行后我们得到的是这个效果:
在加锁以后我们写入的数据就不会被覆盖掉,就可以得到我们需要的数据了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。