目录
fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
(1)在父进程中,fork返回新创建子进程的进程ID;
(2)在子进程中,fork返回0;
(3)如果出现错误,fork返回一个负值。
在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
一、理论
问1. 什么是程序,什么是进程,有什么区别?
问2. 如何查看系统中有哪些进程?
问3. 什么是进程标识符?
问4. 什么叫父进程,什么叫子进程?
问5. C程序的存储空间是如何分配?
问1. 什么是程序,什么是进程,有什么区别?
程序是静态的概念,gcc xxx.c –o pro
磁盘中生成pro文件,叫做程序
进程是程序的一次运行活动,
通俗点意思是程序跑起来了,系统中就多了一个进程
问2. 如何查看系统中有哪些进程?
a.使用ps指令查看
实际工作中,配合grep来查找程序中是否存在某一个进程
CLC@Embed_Learn:~/process$ ps -aux | grep init
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
root 1 0.0 0.1 24604 2496 ? Ss Aug22 0:02 /sbin/init
CLC 44006 0.0 0.0 13592 936 pts/4 S+ 12:47 0:00 grep --color=auto init
b.使用top指令查看,类似windows任务管理器
CLC@Embed_Learn:~/process$ top
top - 12:49:58 up 6 days, 6:25, 2 users, load average: 0.08, 0.10, 0.06
Tasks: 326 total, 1 running, 323 sleeping, 2 stopped, 0 zombie
Cpu(s): 23.1%us, 7.7%sy, 0.0%ni, 69.2%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 2042368k total, 1929468k used, 112900k free, 129160k buffers
Swap: 5998588k total, 5688k used, 5992900k free, 1011552k cachedPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
44008 CLC 20 0 17468 1500 976 R 33 0.1 0:00.51 top
1 root 20 0 24604 2496 1348 S 0 0.1 0:02.21 init
2 root 20 0 0 0 0 S 0 0.0 0:00.15 kthreadd
3 root 20 0 0 0 0 S 0 0.0 0:05.18 ksoftirqd/0
5 root 0 -20 0 0 0 S 0 0.0 0:00.00 kworker/0:0H
7 root 20 0 0 0 0 S 0 0.0 16:09.23 rcu_sched
8 root 20 0 0 0 0 S 0 0.0 13:57.84 rcuos/0
9 root 20 0 0 0 0 S 0 0.0 12:30.63 rcuos/1
10 root 20 0 0 0 0 S 0 0.0 12:54.56 rcuos/2
11 root 20 0 0 0 0 S 0 0.0 12:07.60 rcuos/3
12 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/4
13 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/5
14 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/6
15 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/7
16 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/8
17 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/9
18 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/10
19 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/11
20 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/12
21 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/13
22 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/14
23 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/15
24 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/16
25 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/17
26 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/18
27 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/19
28 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/20
29 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/21
30 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/22
31 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/23
32 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/24
33 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/25
34 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/26
35 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/27
36 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/28
37 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/29
38 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/30
39 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/31
40 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/32
41 root 20 0 0 0 0 S 0 0.0 0:00.00 rcuos/33
问3. 什么是进程标识符?
每个进程都有一个非负整数表示的唯一ID,
叫做pid,类似身份证
Pid=0: 称为交换进程(swapper)
作用—进程调度
Pid=1:init进程
作用—系统初始化
编程调用getpid函数获取自身的进程标识符
getppid获取父进程的进程标识符
问4. 什么叫父进程,什么叫子进程
进程A创建了进程B
那么A叫做父进程,B叫做子进程,父子进程是相对的概念,理解为人类中的父子关系
问5. C程序的存储空间是如何分配?
代码段:存放函数体的二进制代码,由操作系统进行管理
数据段:初始化过的变量
BSS:函数外来初始化的变量
堆:malloc申请空间在堆里申请
栈:函数调用产生以及一些局部变量的信息
进程创建实战
使用fork函数创建一个进程
pid_t fork(void);
fork函数调用成功,返回两次
返回值为0, 代表当前进程是子进程
返回值非负数,代表当前进程为父进程
调用失败,返回-1
fork创建一个子进程的一般目的
fork编程实战
vfork函数 也可以创建进程,与fork有什么区别
关键区别一:
vfork 直接使用父进程存储空间,不拷贝。
关键区别二:
vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。
进程退出
正常退出
补充:
异常退出
等待子进程
为啥要等待子进程退出?
父进程等待子进程退出,并收集子进程的退出状态
子进程退出状态不被收集,变成僵死进程(僵尸进程)
相关函数
status参数:
是一个整型数指针
非空:
子进程退出状态放在它所指向的地址中。
空:
不关心退出状态
孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程
Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程
exec族函数
精彩博文:
为什么要用exec族函数,有什么作用 ?
exec配合fork使用
实现功能,当父进程检测到输入为1的时候,创建子进程把配置文件的字段值修改掉。
system函数
system()函数的返回值如下:
成功,则返回进程的状态值;
当sh不能执行时,返回127;
失败返回-1;
popen函数
https://blog.csdn.net/libinbin_1014/article/details/51490568 http://3
比system在应用中的好处:
可以获取运行的输出结果
二、编程实战
二、进程 process
重点:1 2 3 4 5 12 131. demo1 进程的相关概念
2 3. demo2 - demo6 研究父子进程 demo6.1 创建进程函数fork的使用补充
4. demo7 定义一个全局变量 int data = 10,父进程里面不变,子进程里面做改变。
5. demo8 模拟网络创建子进程对接
6. demo9 fork()函数的使用。
demo10 vfork()函数的使用。
demo11 进程退出
7. 进程退出的详解,exit (),_exit()或者_Exit(),包含前两种。
8. 等待子进程退出
demo12 僵尸进程 ps -aux|grep newpro
demo13 fork()函数 变成僵尸进程。
demo14 使用wait(NULL)函数,等待子进程结束完之后,在执行父进程。
demo15 使用 wait(&status);收集子进程的状态码
9. demo16 有问题,父子不能一块输出。
demo17 孤儿进程的案例,用linux中的init进程收留孤儿进程,编程孤儿进程的父进程。
10. demo18 echorag 我们先用gcc编译echoarg.c,生成可执行文件echoarg并放在 ./echoarg目录下。
文件echoarg的作用是打印命令行参数。然后再编译demo18.c并执行a.out可执行文件。
用 a.out找到并执行echoarg,将当前进程main替换掉,所以"after execl" 没有在终端被打印出来。
demo19 execl,先使用 whereis ls,查看绝对路径/bin/ls,然后在demo19 中改为如下的代码: if(execl("/bin/ls","ls",NULL,NULL) == -1),
然后再编译demo19.c并执行a.out可执行文件,即可当whereis ls指令来使用。
demo20 execl,ls -l指令可以查看文件权限,在demo20中 使用 if(execl("/bin/ls","ls","-l",NULL) == -1),
然后再编译demo20.c并执行a.out可执行文件,可以当做ls -l 指令来使用。
demo21 execl,在系统中可以用date指令来查看时间,可以使用whereis date指令来查看绝对路径,然后在demo21中做代码的修改,
如 if(execl("/bin/date","date",NULL,NULL) == -1)
demo22 execl,使用ps,if(execl("/bin/ps","ps","-l",NULL) == -1)。
demo23 execlp,exaclp函数带p,所以能通过环境变量PATH查找到可执行文件ps,if(execlp("ps","ps","-l",NULL) == -1) 带p不需要加绝对路径
demo24 execvp,把 argv 传到 execvp 中来,char *argv[] = {"ps",NULL,NULL} if(execvp("ps",argv) == -1) 带p不需要加绝对路径
demo25 execv,需要加绝对路径if(execv("/bin/ps",argv) == -1)
11. demo26 fork的使用,用demo26中的a./out把config.txt中的数字改为5。
demo27 exec配合fork使用。 在file文件的demo14,把该代码生成changData,gcc demo14.c -o changData
拷贝changData到process文件中,cp ../file/changData .
代码就可以执行了,好处是代码简洁
12. demo28 system函数的使用,system("./changData config.txt ");
demo29 cp demo24 demo29 使用system函数,如果ps写错了如if(system("psxxx") == -1),结果sh: 1: psxxx: not found 等价于指令:sh -c ps112
13. demo30 demo31 popen的用法:可以得到这个指令的运行结果,可以把结果存到字符串数组,也可以写在文件里。
14. 总结进程
demo1.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = getpid();
printf("my pid is %d\n",pid);
while(1);
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo1.c
CLC@Embed_Learn:~/process$ ./a.out
my pid is 43885
demo2.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = getpid();
fork();
printf("my pid is %d\n",pid);
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo2.c
CLC@Embed_Learn:~/process$ ./a.out
my pid is 43910
my pid is 43910
demo3.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = getpid();
fork();
printf("my pid is %d,current pro id:%d\n",pid,getpid());
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo3.c
CLC@Embed_Learn:~/process$ ./a.out
my pid is 43939,current pro id:43939
my pid is 43939,current pro id:43940
demo4.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = getpid();
fork();
if(pid == getpid()){
printf("this is father prinf,father pid%d\n",getpid());
}else{
printf("this is child ,child pid%d\n",getpid());
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo4.c
CLC@Embed_Learn:~/process$ ./a.out
this is father prinf,father pid43952
this is child ,child pid43953
demo5.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid_t pid2;
pid = getpid();
printf("before fork:pid = %d\n",pid);
fork();
pid2 = getpid();
printf("after fork:pid = %d\n",pid2);
if(pid == pid2){
printf("this is father print\n");
}else{
printf("this is child ,child pid%d\n",getpid());
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo5.c
CLC@Embed_Learn:~/process$ ./a.out
before fork:pid = 43993
after fork:pid = 43993 //fork以后还是由父进程在做
this is father print //父进程就执行完毕了
after fork:pid = 43994 //子进程在做
this is child ,child pid43994 //子进程打印
demo6.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
printf("father: id = %d\n",getpid());
pid = fork();
if(pid > 0){
printf("this is father print ,father pid = %d\n",getpid());
}else if(pid == 0){
printf("this is child ,child pid = %d\n",getpid());
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo6.c
CLC@Embed_Learn:~/process$ ./a.out
father: id = 44331
this is father print ,father pid = 44331
this is child ,child pid = 44332我不知道pid>0是父进程,但是9行和14行获得的getpid却是一样的,由此推断而来,继续demo6.1验证
demo6.1.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid_t pid2;
pid_t retpid;
pid = getpid();
printf("before fork: pid = %d\n",pid);
retpid = fork();
pid2 = getpid();
printf("after fork: pid = %d\n",pid2);
if(pid == pid2){
printf("this is father print: retpid = %d\n",retpid);
}
else{
printf("this id child print: retpid = %d,child pid = %d\n",retpid,getpid());
}
return 0;
}
/*
before fork: pid = 5794
after fork: pid = 5794
this is father print: retpid = 5795
after fork: pid = 5795
this id child print: retpid = 0,child pid = 5795
第14行的fork()不是真正意义上的返回两次,retpid被拷贝了一份,一份给子进程,一份给父进程,在父进程打印的时候中retpid>0,并且等于子进程的id号;
如果retpid=0的话,是说明被分配给了子进程了,只有子进程打印的时候retpid才等于0。
*/
CLC@Embed_Learn:~/process$ gcc demo6.1.c
CLC@Embed_Learn:~/process$ ./a.out
before fork: pid = 44293
after fork: pid = 44293
this is father print: retpid = 44294
after fork: pid = 44294
this id child print: retpid = 0,child pid = 44294第14行的fork()不是真正意义上的返回两次,retpid被拷贝了一份,一份给子进程,一份给父进程,在父进程打印的时候中retpid>0,并且等于子进程的id号;
如果retpid=0的话,是说明被分配给了子进程了,只有子进程打印的时候retpid才等于0。
demo7.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
int data = 10;
printf("father: id = %d\n",getpid());
pid = fork();
if(pid > 0){
printf("this is father print\n");
}else if(pid == 0){
printf("this is child ,child pid = %d\n",getpid());
//data = data +100;
}
printf("data = %d\n",data);
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo7.c
CLC@Embed_Learn:~/process$ ./a.out
father: id = 44439
this is father print
data = 10
this is child ,child pid = 44440
data = 10
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
int data = 10;
printf("father: id = %d\n",getpid());
pid = fork();
if(pid > 0){
printf("this is father print\n");
}else if(pid == 0){
printf("this is child ,child pid = %d\n",getpid());
data = data +100;
}
printf("data = %d\n",data);
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo7.c
CLC@Embed_Learn:~/process$ ./a.out
father: id = 44439
this is father print
data = 10
this is child ,child pid = 44440
data = 110
demo8.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
int data = 10;
while(1){
printf("please input a data\n");
scanf("%d",&data);
if(data == 1){
pid = fork();
if(pid > 0){
}else if(pid == 0){
while(1){
printf("do net request,pid=%d\n",getpid());
sleep(3);
}
}
}else{
printf("wait, do nothing\n");
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo8.c
CLC@Embed_Learn:~/process$ ./a.out
please input a data
2
wait, do nothing
please input a data
1
please input a data
do net request,pid=44555
do net request,pid=44555
do net request,pid=44555......
demo9.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
if(pid > 0){
while(1){
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo9.c
CLC@Embed_Learn:~/process$ ./a.out
this is father print,pid = 38629
this is child print,pid = 38630
this is child print,pid = 38630
this is father print,pid = 38629......
fork取决于进程的调度,父和子都早争夺cpu
demo10.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = vfork();
if(pid > 0){
while(1){
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo10.c
CLC@Embed_Learn:~/process$ ./a.out
this is child print,pid = 44588
this is child print,pid = 44588
this is child print,pid = 44588......
vfork都是子进程先执行
demo11.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = vfork();
if(pid > 0){
while(1){
printf("cnt = %d\n",cnt);
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
//break;
exit(0);
}
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo11.c
CLC@Embed_Learn:~/process$ ./a.out
this is child print,pid = 3434
this is child print,pid = 3434
this is child print,pid = 3434
cnt = 3
this is father print,pid = 3433
cnt = 3
this is father print,pid = 3433
cnt = 3
this is father print,pid = 3433
cnt = 3......
子进程运行3次后,在退出
demo12.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = vfork();
if(pid > 0){
while(1){
printf("cnt = %d\n",cnt);
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
//break;
exit(0);
}
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo12.c -o newpro
CLC@Embed_Learn:~/process$ ./newpro
this is child print,pid = 3566
this is child print,pid = 3566
this is child print,pid = 3566
cnt = 3
this is father print,pid = 3565
cnt = 3
this is father print,pid = 3565
cnt = 3
...
使用vfork(),子进程退出状态不被收集,变成僵尸进程CLC@Embed_Learn:~/process$ ps -aux|grep newpro
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
CLC 3565 0.0 0.0 4160 424 pts/1 S+ 19:40 0:00 ./newpro
CLC 3566 0.0 0.0 0 0 pts/1 Z+ 19:40 0:00 [newpro] <defunct>//子进程3566变成僵尸进程
CLC 3568 0.0 0.0 13588 940 pts/2 S+ 19:40 0:00 grep --color=auto newpro
demo13.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = fork();
if(pid > 0){
while(1){
printf("cnt = %d\n",cnt);
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
//break;
exit(0);
}
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo13.c -o newpro
CLC@Embed_Learn:~/process$ ./newpro
cnt = 0
this is father print,pid = 3842
this is child print,pid = 3843
cnt = 0
this is child print,pid = 3843
this is father print,pid = 3842
this is child print,pid = 3843
cnt = 0
this is father print,pid = 3842
cnt = 0
this is father print,pid = 3842......
使用fork(),子进程退出状态不被收集,变成僵尸进程
CLC@Embed_Learn:~/process$ ps -aux|grep newpro
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
CLC 3842 0.0 0.0 4160 352 pts/1 S+ 19:52 0:00 ./newpro
CLC 3843 0.0 0.0 0 0 pts/1 Z+ 19:52 0:00 [newpro] <defunct>//子进程3483变成了僵尸进程
CLC 3845 0.0 0.0 13592 940 pts/2 S+ 19:52 0:00 grep --color=auto newpro
demo14.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = fork();
if(pid > 0){
wait(NULL);
while(1){
printf("cnt = %d\n",cnt);
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
//break;
exit(0);
}
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo14.c
CLC@Embed_Learn:~/process$ ./a.out
使用wait(), 收集僵尸进程
this is child print,pid = 39352
this is child print,pid = 39352
this is child print,pid = 39352
cnt = 0
this is father print,pid = 39351
cnt = 0
this is father print,pid = 39351
cnt = 0
...在下面中没有39352这个子进程,子进程不会变成僵尸进程
CLC@Embed_Learn:~$ ps -aux|grep a.out
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
CLC 39121 0.0 0.0 4160 428 pts/1 T 13:17 0:00 ./a.out
CLC 39122 0.0 0.0 0 0 pts/1 Z 13:17 0:00 [a.out] <defunct>
CLC 39249 0.0 0.0 4160 428 pts/1 T 13:18 0:00 ./a.out
CLC 39250 0.0 0.0 0 0 pts/1 Z 13:18 0:00 [a.out] <defunct>
CLC 39305 0.0 0.0 4160 352 pts/1 T 13:44 0:00 ./a.out
CLC 39306 0.0 0.0 0 0 pts/1 Z 13:44 0:00 [a.out] <defunct>
CLC 39337 0.0 0.0 4160 352 pts/1 T 13:48 0:00 ./a.out
CLC 39341 0.0 0.0 4160 348 pts/1 T 13:48 0:00 ./a.out
CLC 39351 0.0 0.0 4160 352 pts/1 S+ 13:50 0:00 ./a.out
CLC 39354 0.0 0.0 13592 948 pts/2 S+ 13:50 0:00 grep --color=auto a.out
demo15.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
int status = 10;
pid = fork();
if(pid > 0){
wait(&status);
printf("child quit,child status = %d\n",WEXITSTATUS(status));
wait(NULL);
while(1){
printf("cnt = %d\n",cnt);
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
//break;
exit(3);
}
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo15.c
CLC@Embed_Learn:~/process$ ./a.out
this is child print,pid = 3879
this is child print,pid = 3879
this is child print,pid = 3879
child quit,child status = 3 //子进程退出的状态解析出来了
cnt = 0
this is father print,pid = 3878
cnt = 0
this is father print,pid = 3878
cnt = 0
demo16.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
int status = 10;
pid = fork();
if(pid > 0){
// wait(&status);
waitpid(pid,&status,WNOHANG);
printf("child quit,child status = %d\n",WEXITSTATUS(status));
wait(NULL);
while(1){
printf("cnt = %d\n",cnt);
printf("this is father print,pid = %d\n",getpid());
sleep(1);
}
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 5){
//break;
exit(3);
}
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo16.c
CLC@Embed_Learn:~/process$ ./a.out
child quit,child status = 0
this is child print,pid = 4118
this is child print,pid = 4118
this is child print,pid = 4118
this is child print,pid = 4118
this is child print,pid = 4118
cnt = 0
this is father print,pid = 4117
cnt = 0
this is father print,pid = 4117
cnt = 0.......
waitpid以非阻塞的方式,CLC@Embed_Learn:~$ ps -aux|grep a.out,子进程还是会变成僵尸进程
demo17.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
//int status = 10;
pid = fork();
if(pid > 0){
printf("this is father print,pid = %d\n",getpid());
}else if(pid == 0){
while(1){
printf("this is child print,pid = %d,my father pid = %d\n",getpid(),getppid());
sleep(1);
cnt++;
if(cnt == 5){
//break;
exit(3);
}
}
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo17.c -o guer
CLC@Embed_Learn:~/process$ ./guer
this is father print,pid = 4182
CLC@Embed_Learn:~/process$ this is child print,pid = 4183,my father pid = 1
this is child print,pid = 4183,my father pid = 1
this is child print,pid = 4183,my father pid = 1
this is child print,pid = 4183,my father pid = 1
this is child print,pid = 4183,my father pid = 1Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程
Pid=1:init进程,作用—系统初始化
CLC@Embed_Learn:~/process$ ps -aux|grep guer
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
CLC 4183 0.0 0.0 4160 84 pts/1 S 22:56 0:00 ./guer
CLC 4185 0.0 0.0 13588 940 pts/2 S+ 22:56 0:00 grep --color=auto guer
demo18.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
if(execl("./echoarg","echoarg","abc",NULL) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
echoarg.c
#include <stdio.h>
int main(int argc,char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo18.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
argv[0]: echoarg
argv[1]: abc
demo19.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
if(execl("/bin/ls","ls",NULL,NULL) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo19.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
a.out demo13.c demo1.c demo26.c demo3.c demo9.c newpro
changData demo14.c demo20.c demo27.c demo4.c echoarg
config.txt demo15.c demo21.c demo28.c demo5.c echoarg.c
damo17.c demo16.c demo22.c demo29.c demo6.1.c forktest
demo10.c demo17.c demo23.c demo2.c demo6.c guer
demo11.c demo18.c demo24.c demo30.c demo7.c mydemo
demo12.c demo19.c demo25.c demo31.c demo8.c new
demo20.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
if(execl("/bin/ls","ls","-l",NULL) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo20.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
total 232
-rwxr-xr-x 1 CLC book 8481 Aug 29 00:23 a.out
-rwxr-xr-x 1 CLC book 8785 Dec 17 2020 changData
-rw-r--r-- 1 CLC book 33 Apr 11 2021 config.txt
-rw-r--r-- 1 CLC book 0 Nov 19 2020 damo17.c
-rw-r--r-- 1 CLC book 331 Nov 18 2020 demo10.c......
-rwxr-xr-x 1 CLC book 8431 Dec 16 2020 mydemo
-rwxr-xr-x 1 CLC book 8640 Nov 18 2020 new
-rwxr-xr-x 1 CLC book 8583 Aug 28 19:52 newpro
demo21.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("this is syetem time: \n");
if(execl("/bin/date","date",NULL,NULL) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo21.c
CLC@Embed_Learn:~/process$ ./a.out
this is syetem time:
Mon Aug 29 00:24:48 CST 2022
demo22.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
if(execl("/bin/ps","ps","-l",NULL) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo22.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1000 3110 3103 0 80 0 - 7002 wait pts/1 00:00:00 bash
0 T 1000 3433 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
1 Z 1000 3434 3433 0 80 0 - 0 exit pts/1 00:00:00 a.ou <defunct>
0 T 1000 3448 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
1 Z 1000 3449 3448 0 80 0 - 0 exit pts/1 00:00:00 a.ou <defunct>
0 T 1000 3554 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
1 Z 1000 3555 3554 0 80 0 - 0 exit pts/1 00:00:00 a.ou <defunct>
0 T 1000 3565 3110 0 80 0 - 1040 signal pts/1 00:00:00 newpro
1 Z 1000 3566 3565 0 80 0 - 0 exit pts/1 00:00:00 newp <defunct>
0 T 1000 3842 3110 0 80 0 - 1040 signal pts/1 00:00:00 newpro
1 Z 1000 3843 3842 0 80 0 - 0 exit pts/1 00:00:00 newp <defunct>
0 T 1000 3878 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 T 1000 3903 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 T 1000 4068 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 T 1000 4117 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 R 1000 4408 3110 0 80 0 - 3482 - pts/1 00:00:00 ps
demo23.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
if(execlp("ps","ps","-l",NULL) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo23.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1000 3110 3103 0 80 0 - 7002 wait pts/1 00:00:00 bash
0 T 1000 3433 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
1 Z 1000 3434 3433 0 80 0 - 0 exit pts/1 00:00:00 a.out <defunct>
0 T 1000 3448 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
1 Z 1000 3449 3448 0 80 0 - 0 exit pts/1 00:00:00 a.out <defunct>
0 T 1000 3554 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
1 Z 1000 3555 3554 0 80 0 - 0 exit pts/1 00:00:00 a.out <defunct>
0 T 1000 3565 3110 0 80 0 - 1040 signal pts/1 00:00:00 newpro
1 Z 1000 3566 3565 0 80 0 - 0 exit pts/1 00:00:00 newpro <defunct>
0 T 1000 3842 3110 0 80 0 - 1040 signal pts/1 00:00:00 newpro
1 Z 1000 3843 3842 0 80 0 - 0 exit pts/1 00:00:00 newpro <defunct>
0 T 1000 3878 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 T 1000 3903 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 T 1000 4068 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 T 1000 4117 3110 0 80 0 - 1040 signal pts/1 00:00:00 a.out
0 R 1000 4431 3110 0 80 0 - 3482 - pts/1 00:00:00 ps带p不需要加绝对路径
demo24.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
// char *argv[] = {"ps","-l",NULL};
// if(execvp("ps",argv) == -1)
char *argv[] = {"ps",NULL,NULL}; //定义指针数组 多个指针
if(execvp("ps",argv) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo24.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
PID TTY TIME CMD
3110 pts/1 00:00:00 bash
3433 pts/1 00:00:00 a.out
3434 pts/1 00:00:00 a.out <defunct>
3448 pts/1 00:00:00 a.out
3449 pts/1 00:00:00 a.out <defunct>
3554 pts/1 00:00:00 a.out
3555 pts/1 00:00:00 a.out <defunct>
3565 pts/1 00:00:00 newpro
3566 pts/1 00:00:00 newpro <defunct>
3842 pts/1 00:00:00 newpro
3843 pts/1 00:00:00 newpro <defunct>
3878 pts/1 00:00:00 a.out
3903 pts/1 00:00:00 a.out
4068 pts/1 00:00:00 a.out
4117 pts/1 00:00:00 a.out
4442 pts/1 00:00:00 ps
demo25.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
// char *argv[] = {"ps","-l",NULL};
// if(execvp("ps",argv) == -1)
char *argv[] = {"ps",NULL,NULL};
if(execv("/bin/ps",argv) == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo25.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
PID TTY TIME CMD
3110 pts/1 00:00:00 bash
3433 pts/1 00:00:00 a.out
3434 pts/1 00:00:00 a.out <defunct>
3448 pts/1 00:00:00 a.out
3449 pts/1 00:00:00 a.out <defunct>
3554 pts/1 00:00:00 a.out
3555 pts/1 00:00:00 a.out <defunct>
3565 pts/1 00:00:00 newpro
3566 pts/1 00:00:00 newpro <defunct>
3842 pts/1 00:00:00 newpro
3843 pts/1 00:00:00 newpro <defunct>
3878 pts/1 00:00:00 a.out
3903 pts/1 00:00:00 a.out
4068 pts/1 00:00:00 a.out
4117 pts/1 00:00:00 a.out
4454 pts/1 00:00:00 ps
demo26.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int data = 10;
while(1){
printf("please input a data\n");
scanf("%d",&data);
if(data == 1){
pid = fork();
if(pid > 0){
wait(NULL);
}
if(pid == 0){
int fdSrc;
char *readBuf = NULL;
fdSrc = open("config.txt",O_RDWR);
int size = lseek(fdSrc,0,SEEK_END);
lseek(fdSrc,0,SEEK_SET);
readBuf = (char *)malloc(sizeof(char)*size + 8);
int n_read = read(fdSrc,readBuf,size);
char *p = strstr(readBuf,"LENG=");
if(p==NULL){
printf("not found\n");
exit(-1);
}
p = p+strlen("LENG=");
*p = '5';
lseek(fdSrc,0,SEEK_SET);
int n_write = write(fdSrc,readBuf,strlen(readBuf));
close(fdSrc);
printf("success!!!");
exit(0);
}
}else{
printf("wait, do nothing\n");
}
}
return 0;
}
config.txt
PEED=5
LENG=3
SCORE=90
LEVEL=95
CLC@Embed_Learn:~/process$ gcc demo26.c
CLC@Embed_Learn:~/process$ ./a.out
please input a data
1
success!!!please input a data
2
wait, do nothing
please input a data
3
wait, do nothing
CLC@Embed_Learn:~/process$ cat config.txt
PEED=5
LENG=5
SCORE=90
LEVEL=95
demo27.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int data = 10;
while(1){
printf("please input a data\n");
scanf("%d",&data);
if(data == 1){
pid = fork();
if(pid > 0){
wait(NULL);
}
if(pid == 0){
execl("./changData","changData","config.txt",NULL);
// exit(0); //zhe ge cheng xu yong bu le
}
}else{
printf("wait, do nothing\n");
}
}
return 0;
}
config.txt
PEED=5
LENG=3
SCORE=90
LEVEL=95
CLC@Embed_Learn:~/process$ gcc demo27.c
CLC@Embed_Learn:~/process$ ./a.out
please input a data
2
wait, do nothing
please input a data
1
please input a data
CLC@Embed_Learn:~/process$ cat config.txt
PEED=5
LENG=5
SCORE=90
LEVEL=95
demo28.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int data = 10;
while(1){
printf("please input a data\n");
scanf("%d",&data);
if(data == 1){
pid = fork();
if(pid > 0){
wait(NULL);
}
if(pid == 0){
//execl("./changData","changData","config",NULL);
//exit(0); //zhe ge cheng xu yong bu le
system("./changData config.txt ");
}
}else{
printf("wait, do nothing\n");
}
}
return 0;
}
config.txt
PEED=5
LENG=3
SCORE=90
LEVEL=95
CLC@Embed_Learn:~/process$ gcc demo28.c
CLC@Embed_Learn:~/process$ ./a.out
please input a data
2
wait, do nothing
please input a data
1
please input a data
CLC@Embed_Learn:~/process$ cat config.txt
PEED=5
LENG=5
SCORE=90
LEVEL=95
demo29.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
// char *argv[] = {"ps","-l",NULL};
// if(execvp("ps",argv) == -1)
// char *argv[] = {"ps",NULL,NULL};
if(system("ps") == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo29.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
PID TTY TIME CMD
3460 pts/2 00:00:00 bash
4717 pts/2 00:00:00 a.out
4718 pts/2 00:00:00 sh
4719 pts/2 00:00:00 ps
after execl
demo291.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
// char *argv[] = {"psxxx","-l",NULL};
// if(execvp("ps",argv) == -1)
// char *argv[] = {"ps",NULL,NULL};
if(system("ps") == -1)
{
printf("execl failed!\n");
perror("why: ");
}
printf("after execl\n");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo291.c
CLC@Embed_Learn:~/process$ ./a.out
before execl
sh: 1: psxxx: not found
after execl等价于
CLC@Embed_Learn:~/process$ sh -c ps112
sh: 1: ps112: not found
demo30.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
system("ps");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo30.c
CLC@Embed_Learn:~/process$ ./a.out
PID TTY TIME CMD
3460 pts/2 00:00:00 bash
4808 pts/2 00:00:00 a.out
4809 pts/2 00:00:00 sh
4810 pts/2 00:00:00 ps
demo31.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
char ret[1024] = {0};
FILE *fp;
fp = popen("ps","r");
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int nread = fread(ret,1,1024,fp);
printf("read %d byte,ret = %s\n",nread,ret);
system("ps");
return 0;
}
CLC@Embed_Learn:~/process$ gcc demo31.c
CLC@Embed_Learn:~/process$ ./a.out
read 141 byte,ret = PID TTY TIME CMD
3460 pts/2 00:00:00 bash
4818 pts/2 00:00:00 a.out
4819 pts/2 00:00:00 sh
4820 pts/2 00:00:00 psPID TTY TIME CMD
3460 pts/2 00:00:00 bash
4818 pts/2 00:00:00 a.out
4819 pts/2 00:00:00 sh <defunct>
4821 pts/2 00:00:00 sh
4822 pts/2 00:00:00 ps如果我//printf,则不会输出在屏幕中,原先没有管结果的时候,它一股脑的往屏幕上打,现在我把该往屏幕上打的,全都捕获到字符数组中来。
popen的用法/好处:可以得到这个指令的运行结果,可以把结果存到字符串数组,也可以写在文件里。