Qt进程和线程

1. 进程 QProcess

1.1 知识点

在c语言中:

使用fork函数,由当前进程创建一个子进程,fork的子进程和父进程代码完全一致

在QT中:

QProcess类:额外执行新的程序,执行程序后就是一个新的进程执行

QProcess:进程管理类,使用QProcess类可以操作进程

start(程序的路径):启动进程

注意

一个进程管理对象同时只能创建一个进程执行,当被管理的进程结束,可以启动下一个进程执行

1.2信号

绑定started() 信号,这个信号用来判断进程是否创建成功

绑定finished(int,QProcess::ExitStatus)信号,判断进程是否结束

绑定readyRead()信号,判断进程是否产生数据

1.3 举例


process

mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include <QProcess>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();
    //启动是否成功的槽
    void process_started();

    //判断进程是否结束的槽
    void process_finshed();

    //判断进程是否产生数据的槽
    void process_readyRead();

private:
    Ui::MainWindow *ui;

    QProcess* process;
};
#endif // MAINWINDOW_H

mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

//进程的使用
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建进程管理对象
    process = new QProcess;

    //绑定started() 信号,这个信号用来判断进程是否创建成功
    connect(process,SIGNAL(started()),this,SLOT(process_started()));

    //绑定finished(int,QProcess::ExitStatus)信号,判断进程是否结束
    connect(process,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(process_finshed()));

    //绑定readyRead()信号,判断进程是否产生数据
    connect(process,SIGNAL(readyRead()),this,SLOT(process_readyRead()));

}

MainWindow::~MainWindow()
{
    delete ui;
}


//启动一个新的进程
void MainWindow::on_pushButton_clicked()
{
    //启动进程
    //start()的参数要传一个路径,比如输入"notepad",会打开一个新的记事本出来
    //重点:一个进程管理对象只能创建一个进程,当被管理进程结束,就可以创建新的进程了
    process->start(ui->lineEdit->text());



}

//是否启动成功
void MainWindow::process_started(){
    qDebug()<<"进程启动成功";
    ui->textEdit->append("创建成功");

}

//判断进程是否结束
void MainWindow::process_finshed(){
    qDebug()<<"进程结束";

    ui->textEdit->append("进程结束");
}

//判断进程是否产生数据,当有数据产生,就读取
void MainWindow::process_readyRead(){
    //在进程产生数据时,读取该进程的数据
    QByteArray data =  process->readAll();
    ui->textEdit->append(data);
}

2. 进程间通信 QSharedMemory

2.1 知识点

核心思想就是使用 QSharedMemory:共享内存

2.2 举例

发送端

process_write

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QSharedMemory>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    //创建共享内存对象
    QSharedMemory* shm;
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //共享内存对象,并指定共内存id
    shm = new QSharedMemory("hqyj");
    //可以这样设置共内存id
//    shm->setKey();

    //创建并映射共享内存,1024是共享内存大小
    shm->create(1024);
    //单独映射也可以
//    shm->attach();

}

Widget::~Widget()
{
    delete ui;
}


//往共享内存中写
void Widget::on_pushButton_clicked()
{
    //获取共享内存首地址
    void* pdata =  shm->data();

    QString src = ui->textEdit->toPlainText();
    //src.toStdString().c_str()
    //src.toStdString()转换为c++标准字符串,c_str() 函将转换为指向以空字符(\0)结尾的 C 字符串    
    memcpy((char*)pdata,src.toStdString().c_str(),1024);
}

接收端

process_read

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QSharedMemory>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;

    //共享内存对象
    QSharedMemory* shm;
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //创建共享内存对象
    shm = new QSharedMemory;

    //指定共享内存的id
    shm->setKey("hqyj");

    //映射共享内存
    shm->attach();
}

Widget::~Widget()
{
    delete ui;
}

//从共享内存中读
void Widget::on_pushButton_clicked()
{
    //将共享内存拷贝到buf
    char buf[1024];
    memcpy(buf,shm->data(),1024);

    ui->textEdit->setText(QString(buf));
}

3. 线程 QThread

3.1 知识点

核心思想就是,在创建一个类继承QThread,然后再新创建的类中重写run()函数执行线程,在主进程中 启动线程

线程:由进程中进行创建,在进程中额外执行一个新的任务就叫做线程。

在进程上下文切换时,系统开销比较大,多个线程在进程中,可以共享进程的资源,而调度方式和进程相同

c语言中

pthread_create(&线程id,属性对象地址,线程起始函数,线程函数的参数);

在QT中

QThread:管理线程(线程开启、线程关闭、线程执行等)

run()函数:线程的执行(当线程执行时,就是执行run函数,QThread类已经由Qt完成,run不能修改----线程任务功能固定)

通过QThread类,派生出新类,派生类 也是线程类,同时重写 run函数实现需要的线程功能,当启动线程时,就执行自己的run作为线程任务

start():启动线程

3.2 信号

void finished():信号,线程结束

void started():信号,线程启动

3.3 举例

thread

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>
#include <thread1.h>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_3_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;

    //实例化线程对象
    thread1* t1;
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"


//线程的使用
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //创建线程对象
    t1 = new thread1;
    t1->str = "hello world";
}

Widget::~Widget()
{
    delete ui;
}


//启动线程
void Widget::on_pushButton_clicked()
{
    //启动
    t1->start();
}

//改变线程打印的内容
void Widget::on_pushButton_3_clicked()
{
    t1->str = ui->lineEdit->text();
}

//停止线程
void Widget::on_pushButton_2_clicked()
{
    t1->stop();
}

thread1.h

cpp 复制代码
#ifndef THREAD1_H
#define THREAD1_H

#include <QThread>
#include <QDebug>

class thread1 : public QThread
{
    Q_OBJECT
public:
    thread1();

    //重写执行线程函数run()
    void run();

    void stop();


    QString str;

    bool ok;//循环标志位

};

#endif // THREAD1_H

thread1.cpp

cpp 复制代码
#include "thread1.h"

thread1::thread1()
{
    ok = true;
}


//执行线程
void thread1::run(){
    while(ok){
        qDebug()<<"thread1打印:"<<str;
        sleep(1);
    }
    qDebug()<<ok;

}

//停止线程
void thread1::stop(){
    ok=false;
}

4. 互斥锁

防止在多线程环境下,多个线程对一个变量同时修改

QMutex:互斥量

QReadWriteLock:读写锁

4.1 举例

还是上面的程序

thread

thread1.h

cpp 复制代码
   //互斥锁变量
    QMutex* mutex;

thread1.cpp

cpp 复制代码
//执行线程
void thread1::run(){
    while(ok){
        mutex->lock();//加锁
        qDebug()<<"thread1打印:"<<str;
        mutex->unlock();//解锁
        sleep(1);
    }
    qDebug()<<ok;

}

widget.h

cpp 复制代码
    //互斥锁变量
    QMutex* mutex;

widget.cpp

cpp 复制代码
//改变线程打印的内容
void Widget::on_pushButton_3_clicked()
{
    mutex->lock();//加锁
    t1->str = ui->lineEdit->text();
    mutex->unlock();//解锁
}

4.2读写锁

读写锁和互斥锁差不多,思想就是

  1. 如果加了读锁,别的线程也可以加读锁,但是如果要去加写锁,就必须等待读锁的释放

  2. 如果加了写锁,别的线程要加锁就必须等待写锁的释放

相关推荐
Ajiang282473530428 分钟前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
盼海32 分钟前
排序算法(五)--归并排序
数据结构·算法·排序算法
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’5 小时前
C++ list (链表)容器
c++·链表·list
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
搬砖的小码农_Sky7 小时前
C语言:数组
c语言·数据结构
机器视觉知识推荐、就业指导7 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
Swift社区8 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman8 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法