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

#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

#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

#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

#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

#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

#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

#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

#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

#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

#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

   //互斥锁变量
    QMutex* mutex;

thread1.cpp

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

}

widget.h

    //互斥锁变量
    QMutex* mutex;

widget.cpp

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

4.2读写锁

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值