QT中的线程

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函数即可.

  1. new 子类对象
  2. start(); 线程已经执行run函数了.

互斥锁QMutex:
我们直到,线程间 可以共享内存,于是他们之间就可以通信.
但是 如果两个线程同时访问同一个资源,就会出现问题, 解决方法—加锁

睡眠函数 静态方法QThread::msleep(int msec)

我们来了解一下互斥锁

互斥锁(同步)

在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,公司部门里,我在使用着打印机打印东西的同时(还没有打印完),别人刚好也在此刻使用打印机打印东西,如果不做任何处理的话,打印出来的东西肯定是错乱的。

在线程里也有这么一把锁——互斥锁(mutex),互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即上锁( lock )和解锁( unlock )。

【互斥锁的特点】:

  1. 原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;

  2. 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;

  3. 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

【互斥锁的操作流程如下】:

  1. 在访问共享资源后临界区域前,对互斥锁进行加锁;

  2. 在访问完成后释放互斥锁导上的锁。在访问完成后释放互斥锁导上的锁;

  3. 对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。

下面是我们老师给的图解,非常的形象

在这里插入图片描述
在这里插入图片描述

线程的演示:

两个头文件

#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);
}

运行后我们得到的是这个效果:

在这里插入图片描述

在加锁以后我们写入的数据就不会被覆盖掉,就可以得到我们需要的数据了

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小镇春风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值