• 【QT开发(10)】QT 进程


    1.1 运行一个新进程

    使用类 QProcess,允许将一个进程堪称一个顺序IO设备。

    在Qt中,QProcess类是用于启动外部进程的类。它可以启动任何可执行文件,包括命令行工具和图形用户界面(GUI)应用程序。

    启动一个线程分4步

    1、在 窗口 类中添加一个私有成员类 QProcess myProcess;

    #include 
    ...
    
    namespace Ui {
    class c;
    
    }
    
    class c : public QDialog
    {
        Q_OBJECT
    public:
        explicit c(QWidget *parent = nullptr);
        ~c();
        QProcess myProcess;
    private:
        Ui::c *ui;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2、在 ui 中添加一个 button 按钮,然后添加信号槽。

    3、信号槽中增加启动进程

    void c::on_pushButton_clicked()
    {
        this->myProcess.start("xfce4-appfinder");
        
        // You can optionally wait for the program to finish by calling waitForFinished()  
        // process->waitForFinished();  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    1.2 QProcess 还可以对一些信号进行关联

    例如将 一个进程的信号和主页面进程的槽关联,实现进程信息显示到主进程。

    1、在 主进程中添加私有槽申明

    private slots:
        void showResult();
        void showState(QProcess::ProcessState);
        void showError();
        void showFinished(int,QProcess::ExitStatus);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在C++中,private slots: 和 private: 是用于定义类成员访问权限的关键字,但它们的作用略有不同。
    private: 关键字用于将成员声明为私有访问权限,这意味着这些成员只能在类的内部访问,包括类的构造函数、方法等。在类的外部,这些成员是不可见的,即使用户试图访问它们也会导致编译错误。
    而 private slots: 则是一种特殊的私有成员,用于在Qt框架中实现信号与槽机制。在这里,slots 是指明一个成员函数是一个Qt槽,它可以在类的外部通过信号调用。虽然这些槽函数是私有的,但它们可以通过信号从类的外部调用。
    因此,将 private slots: 替换为 private: 将导致无法从外部调用槽函数,从而无法实现信号与槽机制。所以,这两个关键字是不能互换的。

    2、构造函数中增加槽和信号的关联

    c::c(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::c)
    {
        ui->setupUi(this);
        //sign combine with slot
        connect(&myProcess,&QProcess::readyRead,this,&c::showResult);
        connect(&myProcess,&QProcess::stateChanged,this,&c::showState);
        connect(&myProcess,&QProcess::errorOccurred,this,&c::showError);
        connect(&myProcess,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(showFinished(int,QProcess::ExitStatus)));
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、然后在 单击按钮的的槽中启动程序的代码

    void c::on_pushButton_3_clicked()
    {
        this->myProcess.start("gzip",QStringList()<<"-c");
    
        // wating to Start
        if (!myProcess.waitForStarted())
        {
            return;
        }
        // process
        this->myProcess.write("qt",100);
        myProcess.closeWriteChannel();
    
        // wating ro finish
        if(!myProcess.waitForFinished()){
            return;
        }
        QByteArray result = myProcess.readAll();
        qDebug()<<"showresult2"<< result;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    完成其他槽showResult()、showState()、showError()、showFinished()的代码

    void c::showResult()
    {
        debug::log(
            "\n\n" \
            " This is a Empty project. \n" \
            " print some vals:\n" \
            "    int    = {0}\n" ,
            std::string{"myProcess.readAll()"}
        );
    	QTextCodec *codec = QTextCodec::codecForLocale();
    	qDebug()<<"showresult"<< codec->toUnicode(myProcess.readAll());
    }
    
    void c::showState(QProcess::ProcessState state)
    {
     qDebug()<<"showState";
     if(state == QProcess::NotRunning){
         qDebug()<<"NotRunning";
     }else if (state == QProcess::Starting){
         qDebug()<<"Starting";
     }else{
          qDebug()<<"Runing";
     }
    }
    void c::showError()
    {
     qDebug()<<"showError";
    }
    void c::showFinished(int,QProcess::ExitStatus exitStatus)
    {
     qDebug()<<"showFinished";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    实现了进程间的信号和槽的“互动”。

    2 进程间通信

    1、使用 TCP/IP
    2、共享内存
    3、 D-BUS
    4、QProcess
    5、会话管理

    在这里插入图片描述

    在这里插入图片描述

    2.1 使用共享内存实现进程通信

    1、使用QShareMemory 类,为其指定一个 key,拥有这个 key 就可以使用这个内存。
    2、在 共享内存中加入数据loadFromFile();

    • 进程和共享内存分离;
    • 申请一个 QBuffer,将图像数据导入QBuffer
        QString fileName = QFileDialog::getOpenFileName(0,QString(),QString(),"*.jpg");
        QImage image;
        QBuffer buffer;
        buffer.open(QBuffer::ReadWrite);
        QDataStream out(&buffer);
        out << image;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 创建共享内存。使用create函数创建指定大小的共享内存段,单位是字节,该函数会自动将共享内存段连接到本进程。
    int size =buffer.size();
    sharedMemory.create(size);// 如果对其具有管理权限,每次都可创建,会删除旧的数据。
    
    • 1
    • 2
    • 对内存进行加锁。然后使用memcpy 进行数据拷贝。完成后解锁。数据加载到内存完成。
        sharedMemory.lock();
        char *to = (char *)sharedMemory.data();
        const char * from = buffer.data().data();
        memcpy(to,from,qMin(sharedMemory.size(),size));
        sharedMemory.unlock();
        // sharedMemory.detach();如果现在断开了这个连接,因为没有其他人在使用这个对象,就会被释放掉,因此不应该断开连接。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3、从共享内存中读取数据LoadFromMemory();

    • 和内存进行连接。
    • 然后使用 QBuffer 进行读取,记得这个过程需要加锁和解锁。
    • 进程和内存进行分离。
        sharedMemory.attach());
        QBuffer buffer;
        QDataStream in(&buffer);
        QImage image;
        sharedMemory.lock();
        buffer.setData((char *)sharedMemory.constData(),sharedMemory.size());
        buffer.open(QBuffer::ReadOnly);
        in >> image;
        sharedMemory.unlock();
        sharedMemory.detach();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们启动两个程序,是两个进程。
    左边的进程上运行:在 共享内存中加入数据loadFromFile();
    右边的进程上运行:从共享内存中读取数据LoadFromMemory();

    可以在2.2 的演示中看到效果。

    需要注意的是,我们左边进程,如果运行LoadFromMemory();,会导致共享内存直接被释放掉,就会导致右边的进程无法使用这个共享进程了。
    如果把LoadFromMemory(); 中释放内存的代码删除,会导致,两个进程都不释放共享内存。在左边进程想更新这个内存sharedMemory.create(size);时可能会报错。

    需要设计这个状态机过程,起始还是有点琐碎的。

    2.2 演示

    请添加图片描述

    代码仓库

    https://gitee.com/hiyanyx/qt5.14-cpp_dds_-project/tree/QTProcess
    分支:QTProcess

    参考

    《Qt Creator快速入门_第三版__霍亚飞编著.pdf》

  • 相关阅读:
    Spring源码-面试题-Bean的生命周期
    中断上下文和进程上下文
    莫比乌斯召回系统介绍
    激光驱动电路中的充电边沿导致激光误点亮问题总结
    极智编程 | 谈谈 C++ 中容器 map 和 unordered_map 的区别
    Kubernetes:云原生时代的核心引擎
    python tempfile 模块使用
    Text2SQL之不装了,我也是RAG
    饲料板块毛利润分析主逻辑SQL
    JS 数据结构:链表
  • 原文地址:https://blog.csdn.net/djfjkj52/article/details/133939367