博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2.1 Linux 启动新进程
阅读量:4111 次
发布时间:2019-05-25

本文共 6357 字,大约阅读时间需要 21 分钟。

启动新进程
  1. system 函数(使用 shell 启动新进程)
  2. exec 函数(替换进程映像,并未创建新的进程)
  3. fork 函数(复制进程映像,创建新进程父子关系:原进程与新进程)

1. system 函数(使用 shell 启动新进程)
  • 在一个程序的内部启动另一个程序,从而创建一个新进程。
  • system 函数确实创建了一个新的进程,但是新进程和原进程之间没有父子关系!仅仅是用一个 shell 来启动想要执行的程序。
  • 缺点:一般来说,使用 system 函数远非启动其他进程的理想手段,因为它 必须用一个 shell 来启动需要的程序。由于在启动程序之前需要先启动一个 shell,而且对 shell 的安装情况及使用环境的依赖也很大,所以使用 system 函数的效率不高。
  1. system 函数
#include 
// 运行以字符串参数的形式传递给它的命令并等待该命令的完成。// 命令的执行情况如同在 shell 中执行如下的命令// $ sh -c stringint system(const char *string);
  1. 在 test1 中启动 test2,test1 代码如下:
/* test1.c */#include 
#include
void main(){
int res; printf("Running test2 with system\n"); // 启动 test2 并等待 test2 执行结束 res = system("./test2"); printf("Done. res=%d\n", res);}

test2 代码如下:

/* test2.c,睡眠 3 秒,模拟耗时操作 */#include 
#include
#include
int main(){
printf("test2 running\n"); sleep(3); printf("test2 done.\n"); exit(0);}

运行 test1,执行结果如下(可以看到 test1 等待 test2 执行返回后,才继续执行):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test1 test1.cubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test2 test2.cubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test1Running test2 with system  // test1 运行test2 running	// test2 开始执行test2 done.		// test2 执行终止Done. res=0 	// test1 运行终止

查看进程信息,查看‘COMMAND’列,可以发现 test2 是通过 命令 ‘sh -c ./test2’ 启动。这里有3个进程,它们依次启动,pid 数值依次递增:

  • (pid:9204)test1 进程
  • (pid:9205)用于启动 test2 的 shell 进程(新进程
  • (pid:9206)test2 进程(新进程
  • 其中 test2 是我们想要启动的进程,而 shell 进程是用来启动 test2 的
ubuntu@cuname:~$ ps uUSER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDubuntu     9204  0.0  0.0   4352   636 pts/18   S+   15:58   0:00 ./test1ubuntu     9205  0.0  0.0   4504   752 pts/18   S+   15:58   0:00 sh -c ./test2ubuntu     9206  0.0  0.0   4352   624 pts/18   S+   15:58   0:00 ./test2

当然也可以让 shell 在后台执行 test2 程序,使得 system 函数在 shell 命令结束后立即返回,将 test1 程序中

res = system("./test2");

修改为

res = system("./test2 &");

再次运行 test1,执行结果如下(可以看到 test1 先执行完毕,随后 test2 才执行结束):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test1 test1.cubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test1Running test2 with systemDone. res=0		// test1 执行结束test2 runningubuntu@cuname:~/dev/beginning-linux-programming/test$ test2 done. // test2 执行结束

2. exec 函数(替换进程映像:原进程执行新程序,并未创建新进程)
  1. exec 函数较多,这里使用 execlp 函数
#include 
// 其参数个数可变,且以一个空指针结束int execlp(const char *file, const char *arg0, ..., (char *)0);
  1. 在 test1 中执行 test2,test1 代码如下:
/* test1.c */#include 
#include
#include
void main(){
int res; printf("Running test2 with exec\n"); execlp("./test2", "aa", "bb", "cc", (char *)0); printf("Done. res=%d\n", res); //}

test2 代码如下:

/* test2.c,首先打印 main 函数接收到的参数 */#include 
#include
#include
int main(int argc, char *argv[]){
printf("test2 running\n"); // 打印参数 if(argc > 1){
for(int i = 0;i < argc;i++){
printf("arg: %s\n", argv[i]); } } // 模拟耗时操作 sleep(5); printf("test2 done.\n"); exit(0);}

运行 test1,执行结果如下(可以看到 test1 的最后一个 printf 语句并没有被执行,而 test2 正确执行完毕):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test1 test1.cubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test2 test2.cubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test1Running test2 with exec 	// test1 开始运行test2 running		// test2 的代码开始被执行arg: aaarg: bbarg: cctest2 done. 		// test2 的代码执行结束,进程终止

test1 执行期间,查看进程信息(其中并没有 test1 进程,而只有 test2 进程如下):

ubuntu@cuname:~$ ps uUSER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDubuntu     9389  0.0  0.0   4352   636 pts/18   S+   16:40   0:00 aa bb cc

原因:在 test1 中调用 exec 函数后,运行中的程序开始执行 exec 调用中指定的新的可执行文件的代码(即:test2),程序并没有再返回到 test1 程序中。新的进程的pid / ppid 和 nice 值与原先的完全一样,只是执行代码做了替换


3. fork 函数(创建新进程,父子关系:原进程与新进程)
  • 通过调用 fork 函数,创建一个新进程。这个系统调用复制当前进程,在进程表中创建一个新的表项,新表项中的许多属性与当前进程是相同的。新进程几乎与原进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间 / 环境和文件描述符。可以先使用 fork 函数创建新进程,然后在新进程中使用 exec 函数替换执行代码
  • 父进程中,fork 函数调用返回的是 新的子进程的 PID
  • 子进程中,fork 函数调用返回的是 0
  • 程序在调用 fork 时被分为两个独立的进程。程序 通过 fork 调用的返回值确定父/子进程
    fork函数调用
  1. fork 函数
#include 
#include
pid_t fork(void);

一个典型的使用 fork 的代码片段如下:

pid_t new_pid;new_pid = fork();switch(new_pid){
case -1: // error break;case 0; // 子进程 break;default: // 父进程 break;}
  1. test1 中 联合使用 fork 和 exec 函数,在新进程中执行 test2 代码,test1 代码如下:
/* test1.c */#include 
#include
#include
#include
void main(){
pid_t pid; printf("parent process: Running test2 with fork/exec\n"); pid = fork(); switch (pid){
case -1: // error printf("error: fork failed.\n"); break; case 0: // 子进程 // 将子进程映像替换为 test2 程序 execlp("./test2", "aa", "bb", "cc", (char *)0); // 子进程终止,下面的 'break;' 语句不会被子进程执行, // 因为子进程的执行代码已经被 test2 程序代码所替换, // 且 test2 执行完毕后,不会返回到原程序中。 break; default: // 父进程 sleep(5); break; } printf("parent process over.\n");}

test2 程序代码如下:

/* test2.c */#include 
#include
#include
int main(int argc, char *argv[]){
printf("test2 running\n"); if(argc > 1){
for(int i = 0;i < argc;i++){
printf("arg: %s\n", argv[i]); } } sleep(5); printf("test2 done.\n"); exit(0);}

执行 test1,运行结果如下:

ubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test1parent process: Running test2 with fork/exectest2 running		// 子进程启动并替换映像为 test2 程序arg: aaarg: bbarg: ccparent process over.	// 父进程终止test2 done.				// 子进程终止

test1 执行期间,进程信息如下(可以看到 父子进程分别为 test1 和 test2,不同于 system 函数,没有使用 shell 进程创建新进程):

ubuntu@cuname:~$ ps uUSER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDubuntu     9617  0.0  0.0   4352   784 pts/18   S+   17:07   0:00 ./test1ubuntu     9618  0.0  0.0   4352   624 pts/18   S+   17:07   0:00 aa bb cc

4. 多进程实验
  1. 下列程序输出结果?
#include 
#include
#include
#include
void main(){
printf("1 running.\n"); fork(); fork(); printf("222\n"); sleep(6);}

程序执行流程如下图:

程序执行流程
输出结果为(printf 语句执行 4次):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test3 test3.cubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test31 running.222222222222

转载地址:http://bclsi.baihongyu.com/

你可能感兴趣的文章
DirectX11 光照演示示例Demo
查看>>
VUe+webpack构建单页router应用(一)
查看>>
Node.js-模块和包
查看>>
(python版)《剑指Offer》JZ01:二维数组中的查找
查看>>
管理用户状态——Cookie与Session
查看>>
Spring MVC中使用Thymeleaf模板引擎
查看>>
PHP 7 的五大新特性
查看>>
深入了解php底层机制
查看>>
PHP中的stdClass 【转】
查看>>
XHProf-php轻量级的性能分析工具
查看>>
OpenCV gpu模块样例注释:video_reader.cpp
查看>>
【增强学习在无人驾驶中的应用】
查看>>
OpenCV meanshift目标跟踪总结
查看>>
就在昨天,全球 42 亿 IPv4 地址宣告耗尽!
查看>>
卧槽!Java 虚拟机竟然还有这些性能调优技巧...
查看>>
听说玩这些游戏能提升编程能力?
查看>>
如果你还不了解 RTC,那我强烈建议你看看这个!
查看>>
沙雕程序员在无聊的时候,都搞出了哪些好玩的小玩意...
查看>>
Mysql复制表以及复制数据库
查看>>
深究Java中的RMI底层原理
查看>>