关闭

QProcess:进程通信之无名管道

标签: 无名管道IPC进程通信QtC++
1589人阅读 评论(1) 收藏 举报
分类:

进程间通信(IPC)方式包括:管道,FIFO,信号。这里只提下无名管道,用于有亲缘关系的进程之间。有名管道可以用在没有亲缘关系的进程之间。

QProcess,底层使用的就是无名管道。

做了一个小demo,毕设有一块要用到。

由于底层封装了win linux mac不同平台的无名管道实现,避免了无谓的跨平台体力劳动。

但使用QProcess时,要注意:在主进程中向子进程写数据时,数据结尾一定要有换行符,即"\n",否则就如同用标准输入没有按回车一个效果,子进程是不会去处理你输入的数据的,因为子进程认为你还没有输完。

用于子进程的程序:

#include <iostream>
#include <string>
using std::cout;
using std::endl;

int main(void)
{
    cout << "Child Process: I am Ready!" << endl;
    std::string input;
    while(true)
    {
        getline(std::cin,input);
        if(!input.compare("quit"))
            break;
        cout << "From Child Process: " << input << endl;
    }
    cout << "Bye From Child Process!" << endl;
    return 0;
}

用于调用上述子程序的主程序,主程序有三个文件组成

#ifndef PARENT_PROCESS_H
#define PARENT_PROCESS_H
#include <QObject>
class QProcess;

class ParentProcess : public QObject
{
    Q_OBJECT
public:
    explicit ParentProcess(QObject *parent = 0);
    ~ParentProcess();
public slots:
    void sender();
    void receiver();
private:
    QProcess* myChildProcess;
    int count;
};

#endif // PARENT_PROCESS_H


#include "ParentProcess.h"
#include <QProcess>
#include <QDebug>

ParentProcess::ParentProcess(QObject *parent) :
    QObject(parent)
{
    count = 0;
    myChildProcess = new QProcess(this);
    QObject::connect(myChildProcess,SIGNAL(readyReadStandardOutput()),this,SLOT(receiver()));
    myChildProcess->setProcessChannelMode(QProcess::MergedChannels);
    myChildProcess->start("usingQProcess.exe");
    if (!myChildProcess->waitForStarted())
        qDebug() << "Make failed:" << myChildProcess->errorString();
    else
        qDebug() << "Child Process Started. " << myChildProcess->readAll();
}

ParentProcess::~ParentProcess()
{
    myChildProcess->close();
    delete myChildProcess;
    myChildProcess = nullptr;
}

void ParentProcess::sender()
{
   if(count > 3)
       myChildProcess->write("quit\n");
   count++;
   myChildProcess->write("Nice to meet you!");
   myChildProcess->write((QString::number(count)+ "\n").toStdString().c_str());
}

void ParentProcess::receiver()
{
    char output[128];
    int ret = myChildProcess->readLine(output,127);
    qDebug() << ret;
    qDebug() << output;
}


#include "ParentProcess.h"
#include <QtWidgets/QApplication>
#include <QtWidgets/QPushButton>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ParentProcess obj;
    QPushButton myBtn;
    myBtn.show();
    QObject::connect(&myBtn,SIGNAL(clicked()),&obj,SLOT(sender()));

    return a.exec();
}

上述程序运行之后,子进程通过标准输入输出 来获取和打印信息,而主程序则通过无名管道,重定向子进程的输入输出。
外部程序未启动时,其状态是NotRunning;
    当启动时,其状态转变为Starting,正在启动,但此时还未调用起来;
    启动之后,继续变为Running,同时发射出started()信号,此时,可以对QProcess进行读写操作了;
    当退出时,其状态改为NotRunning,并发射出finished()信号。finishe()信号会携带退出码和退出状态,可以分别通过exitCode()和exitStatus()来获得。

    当发生错误时,QProcess会发出一个error()信号,同样的,也可以通过error()来获得其错误类型,通过state()获得当前程序的状态。

QProcess继承于QIODevice,因此,我们可以把它当作是一个I/O设备进行读写操作。

QProcess有两种预定义的输出通道:标准输出stdout与标准错误stderr。
    通过setReadChannel()可以选择当前读取输出的通道。
    当通道中的数据准备就绪时,QProcess会发出readyRead()信号。如果是标准输出,则发出readyReadStandardOutput()信号;如果是标准错误,则发出readyReadStandardError()信号。
    常用的读取方式有read(), readAll()或getChar(),也可以通过readAllStandardOutput()和readAllStandardError()读取标准输出和标准错误通道中的数据。
    某些程序需要环境设置才能进行特殊的操作。可以通过setEnvironment()来设置环境变量,通过setWorkingDirectory()来设置工作目录,默认的工作路径是当前调用程序的工作路径。

 QProcess提供了一系列的函数以提到事件循环来完成同步操作:
(1)waitForStarted()          : 阻塞,直到外部程序启动
(2)waitForReadyRead()    : 阻塞,直到输出通道中的新数据可读
(3)waitForBytesWritten()  : 阻塞,直到输入通道中的数据被写入
(4)waitForFinished()        : 阻塞,直到外部程序结束
    如果在主线程(QApplication::exec())中调用这些函数,可能会造成当前用户界面不响应。





0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:94348次
    • 积分:2032
    • 等级:
    • 排名:第18873名
    • 原创:109篇
    • 转载:20篇
    • 译文:1篇
    • 评论:36条
    最新评论