Qt进程-QProcess使用总结

Qt进程

这篇博客主要关于在Qt中使用进程的相关内容,包含有Qt自带的class类QProcess和使用C语言fork出来的进程,两种创建进程的方式。

QProcess

这里主要包含使用QProcess的启动方式以及同步进程相关的API

启动外部程序分为两种方式:

  1. 阻塞式 execute()
QProcess *pCaller = new QProcess();
// 阻塞调用 当前窗口处理结束关闭之后 主窗口才能操作
pCaller->execute("/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1");
  1. 非阻塞式 start()startDetached()
QProcess *pCaller = new QProcess();
// 非阻塞调用 当前窗口的执行状态不影响主窗口的操作
pCaller->startDetached("/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1", QStringList());  
pCaller->start("/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1");

非阻塞式调用分为两种:
(1)一体式: start()

void QProcess::start(const QString & program, const QStringList & arguments, OpenMode mode = ReadWrite)

外部程序启动后,将随主程序的退出而退出。

(2)分离式:startDetached

void QProcess::startDetached(const QString & program, const QStringList & arguments, const QString & workingDirectory = QString(), qint64 * pid = 0

外部程序启动后,当主程序退出时并不退出,而是继续运行。

这里需要注意在获取processId进程ID的时候,由于在非阻塞式分离式启动线程的方法中,有一个参数默认设置为0,因此,获取该方法产生的进程ID是均是0.

Synchronous Process API (同步进程API)

QProcess提供了一系列的函数以提到事件循环来完成同步操作:

(1)waitForStarted(): 阻塞,直到外部程序启动
(2)waitForReadyRead(): 阻塞,直到输出通道中的新数据可读
(3)waitForBytesWritten() : 阻塞,直到输入通道中的数据被写入
(4)waitForFinished(): 阻塞,直到外部程序结束果在主线程(QApplication::exec())中调用这些函数,可能会造成当前用户界面不响应。

实例程序

// Qt进程调用可执行程序
void MainWindow::on_pBtn_Process_clicked()
{
    QProcess *pCaller = new QProcess();
    // 阻塞调用 当前窗口处理结束关闭之后 主窗口才能操作
    // pCaller->execute("/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1");
    // 非阻塞调用 当前窗口的执行状态不影 影响主窗口的操作
    pCaller->start("/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1");
    // startDetached
    // pCaller->startDetached("/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1", QStringList());
    // printf("pCaller->processId() = %d\n", getpid());
    llPid[iPidCnt++] = pCaller->processId();
}

fork子进程

fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。点击这里有更详细关于fork()函数的解释。

实例程序

// C进程 调用可执行程序

int MainWindow::set_cpu(int iCpuID)
{
    cpu_set_t stMask;
    CPU_ZERO(&stMask);
    CPU_SET(iCpuID, &stMask);
    return sched_setaffinity(0, sizeof(cpu_set_t), &stMask);
}
void MainWindow::on_pBtn_OK_clicked()
{
    pid_t stPid;
    stPid = fork();
    set_cpu(0);
    if(stPid < 0){
        printf("创建子进程失败!\n");
        return ;
    }
    if(stPid == 0){
        set_cpu(1);
        int iErr = execl("/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1", "/home/gsk/Qt/build-Demo-child1-Desktop_Qt_5_12_3_GCC_64bit-Debug/Demo-child1", NULL);
        printf("%d\n", iErr);
    }
}

获取进程的ID

在QProcess中,通过Qt中的API processId()可以获取当前进程的ID(需注意,对于start()开启的进程,可以通过该API获取进程ID,但对于startDetached()开启的进程,获取的进程ID是0,关闭该进程,就会关闭系统);在fork产生的进程中可以使用getpid()获取进程ID使用getppid()获取该进程父进程的ID。

关于进程0和进程1:

  • 所有进程的祖先叫做进程0,idle进程或者swapper进程,它是在Linux的初始化阶段从无到有的创建的内核进程(该进程描述符使用的是静态分配的数据结构,其他进程都是动态分配的)
  • 进程0调用start_kernel()函数初始化内核需要的所有数据结构,激活中断,创建一个进程1的内核进程(init进程),进程0和进程1 共享每进程的所有内核数据结构。
  • 多处理器中,每个CPU都有自己的进程0。进程0创建的内核进程执行init()函数初始化内核。然后调用execve()系统调用装入可执行程序init.至此,init为一个普通的进程,且拥有每进程内核数据结构。在系统关闭之前,init一直存在,它创建和监控在操作系统外层的执行的所有进程的活动。

你可能感兴趣的:(#,Qt,QProcess,Qt,进程)