Linux多进程编程1-创建进程

进程的基础操作

获得当前进程的PID

#include <unistd.h>
#include <stdio.h>

int main(int argc, char** argv){
    pid_t pid = getpid();
    printf("进程的PID是:%d\n", pid);
    return 0;
}

进程的PID是:4830

创建进程

  1. 函数
#include<unistd.h>

pid_t fork();

该函数用于创建子进程,子进程被创建后复制父进程的程序内容和变量内容(但不共享变量内存),包括该fork函数。如果进程创建成功,在父进程中,fork函数的返回值为子进程的PID;在子进程中fork函数的返回值为0。看起来就像是fork有两个返回值一样。如果进程创建失败,子进程没有产生,父进程中的fork函数返回-1。

  1. 示例代码
#include <unistd.h>
#include <iostream>
using namespace std;

int main(int argc, char** argv){
    pid_t pid;                          // 用以记录进程的PID
    int counter = 0;                    // 用以证明子进程复制了父进程的程序,但并不是内存共享

    pid = fork();                       // 创建子进程

    if(pid<0){                          // 进程创建失败
        cerr<< "进程创建失败!"<< endl;
        return -1;
    }
    else if(pid==0){                    // 该进程为子进程
        cout<< "我是子进程,PID:"<< getpid()<< endl;
        counter++;
    }
    else{                               // 该进程为父进程
        cout<< "我是父进程,PID:"<< getpid()<< "  我获得的子进程PID为:"<< pid<< endl;
        counter++;
    }

    if(pid==0){
        cout<< "子进程中的counter:"<< counter<< endl;
    }
    else{
        cout<< "父进程中的counter:"<< counter<< endl;
    }

    return 0;
}

我是父进程,PID:7825 我获得的子进程PID为:7826
父进程中的counter:1
我是子进程,PID:7826
子进程中的counter:1

  1. 分析

可以看到,在父进程中我们所获得的子进程的PID和在子进程中所获得的PID是一致的(7826)。同时,子进程虽然在创建时拷贝了父进程的变量,但是,由于子进程与父进程之间不存在内存共享,所以在子进程和父进程中分别修改counter并不能互相影响。另外,子进程和父进程的执行并没有先后顺序,一切都取决于操作系统的调度策略。

替换进程

  1. 函数
#include <unistd.h>
int execl(const char* path, const char* arg, ...);
int execlp(const char* file, const char* arg, ...);
int execle(const char* path, const char* arg, ..., char* const envp[]);

int execv(const char* path, char* const arg[]);
int execvp(const char* file, char* const arg[]);
int execvpe(const char* file, char* const arg[], char* const envp[]);

exec函数族同样可以创建进程,与fork不同的是,exec创建的进程会取代父进程,甚至会占有父进程的PID,实打实的进程界的“鬼上身”。exec函数族中常用的两个函数分别是execl和execlp,下面将通过实例详细介绍。

  • execl

execl的第一个参数是执行文件的路径,第二个参数是该执行文件所需的输入(执行文件传参),和我们main(int argc, char** argv)中的argv部分一样,执行文件传参的第一个参数argv[0]一般是文件名(可以是任何字符,一般设置为文件名或命令名)。从第二个参数argv[1]起才是真正能够在执行文件中发挥作用的参数。当argv中出现NULL时则认为传参结束。一般情况下,执行文件都需要一个argv[0]文件名参数,也就是说argv至少需要一个非null参数(就是我们说的文件名),否则不能正确执行。
函数执行成功时无返回值,执行失败时返回-1.

$ 执行一个不需要传参的执行文件

#include <unistd.h>
using namespace std;

int main(int argc, char** argv){
    execl("/bin/pwd", "pwd", NULL);
    cout<< "=========================="<< endl;
    return 0;
}

/home/torch/code/linux-c++/clion/cmake-build-debug

在这个例子中,我们执行了pwd命令,他是一个不需要参数的命令,因此我们的argv[0]为命令名,并没有实际作用,但必须要有;argv[1]为NULL,表示传参结束。另外,程序并没有输出一串"="号,说明程序被替换为了pwd命令,原来的程序已经不存在了。

$ 执行一个需要传参的执行文件

#include <unistd.h>
using namespace std;

int main(int argc, char** argv){
    execl("/bin/ls", "ls -al", "-al", "/etc/passwd", NULL);
    return 0;
}

/home/torch/code/linux-c++/clion/cmake-build-debug

在这个例子中,我们执行了ls -al /etc/passwd命令,所以我们的argv[0]为"ls -al"并没有实际作用,但必须要有;argv[1]为"-al",argv[2]为"/etc/passwd",argv[3]为NULL,表示传参结束。

$ 如果argv没有任何参数会发生什么?

我们首先写一个被执行程序,并把他编译为test.out,然后执行

/**
 * file name: test.cpp
 */
#include <unistd.h>
#include <iostream>
using namespace std;

int main(int argc, char** argv){
    cout<< "argc: "<< argc<< endl;
    for(int i=0;i<argc;i++){
        cout<< argv[i]<< endl;
    }
    return 0;
}

argc: 1
./test.out

系统自动传递了一个文件名参数给我们的程序,因此检测到一个参数,参数为文件名。

我们再写一个程序通过execl函数执行我们的test.out

#include <unistd.h>
#include <iostream>
using namespace std;

int main(int argc, char** argv){
    execl("./test.out", NULL);
    return 0;
}

argc:1

可以看到,当我们不传递任何参数给执行文件时,编译时会给我们警告,并且函数会自动传递一个空字符参数给我们的执行文件。我们对程序进行修改:

#include <unistd.h>
#include <iostream>
using namespace std;

int main(int argc, char** argv){
    execl("./test.out", "test.out", NULL);
    return 0;
}

argc:1
test.out

此时编译器不再发出警告,test.out获得了我们传递给他的"test.out"字符串。

  • execlp

execlp的第一个参数是环境变量中的文件名,第二个参数和execl一致。相比于execl,execlp专门用来执行已经加入到环境变量中的程序。

$ 示例

#include <unistd.h>
#include <iostream>
using namespace std;

int main(int argc, char** argv){
    execlp("pwd", "pwd", NULL);
    return 0;
}

/home/torch/code/linux-c++/clion/cmake-build-debug

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值