(一)linux系统编程之进程

1.了解进程相关的概念

1.1 程序和进程
程序:二进制文件,占用磁盘空间;进程:启动的程序,所有的数据都在内存中,且需要占用更多的系统资源,占CPU物理内存。
1.2 并行和并发
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生(一个时间段)。
并行是在一台处理器上“同时”处理多个任务,并发是在多台处理器上同时处理多个任务。
1.3 进程控制块PCB
进程控制块(PCB)是系统为了管理进程设置的一个专门的数据结构。系统用它来记录进程的外部特征,描述进程的运动变化过程。同时,系统可以利用PCB来控制和管理进程,所以说,PCB(进程控制块)是系统感知进程存在的唯一标志。
Linux系统的PCB包括很多参数,每个PCB约占1KB多的内存空间。用于表示PCB的结构task_struct简要描述如下:

struct task_struct{
...
unsigned short uid;
int pid;
int processor;
...
volatile long state;
long prority;
unsighed long rt_prority;
long counter;
unsigned long flags;
unsigned long policy;
...
Struct task_struct *next_task, *prev_task;
Struct task_struct *next_run,*prev_run;
Struct task_struct *p_opptr,*p_pptr,*p_cptr,*pysptr,*p_ptr;
...
};

下面对部分数据成员进行说明:
(1)unsigned short pid 为用户标识
(2)int pid 为进程标识
(3)int processor标识用户正在使用的CPU,以支持对称多处理机方式;
(4)volatile long state 标识进程的状态,可为下列六种状态之一:
可运行状态(TASK-RUNING);
可中断阻塞状态(TASK-UBERRUPTIBLE)
不可中断阻塞状态(TASK-UNINTERRUPTIBLE)
僵死状态(TASK-ZOMBLE)
暂停态(TASK_STOPPED)
交换态(TASK_SWAPPING)
(5)long prority表示进程的优先级
(6)unsigned long rt_prority 表示实时进程的优先级,对于普通进程无效
(7)long counter 为进程动态优先级计数器,用于进程轮转调度算法
(8)unsigned long policy 表示进程调度策略,其值为下列三种情况之一:
SCHED_OTHER(值为0)对应普通进程优先级轮转法(round robin)
SCHED_FIFO(值为1)对应实时进程先来先服务算法;
SCHED_RR(值为2)对应实时进程优先级轮转法
(9)struct task_struct *next_task,*prev_task为进程PCB双向链表的前后项指针
(10)struct task_struct *next_run,*prev_run为就绪队列双向链表的前后项指针
(11)struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_ptr指明进程家族间的关系,分别为指向祖父进程、父进程、子进程以及新老进程的指针。
1.4 进程的五种状态
在这里插入图片描述

2.掌握fork/ getpid/ getppid函数在这里插入图片描述

在这里插入图片描述
注:a)fork函数的返回值

>0,父进程的返回值
=0,子进程的返回值

子进程创建成功之后,代码的执行位置?
父进程执行到哪就从哪开始。
父子进程的执行顺序?
顺序不一定。谁抢到CPU谁先执行。
如何区分父子进程?
根据fork返回值,>0为父进程,=0为子进程。
验证fork函数执行顺序和返回值

#include <stdio.h>
#include <unistd.h>//fork头文件
#include <sys/types.h>//getpid  getppid头文件
 #include<sys/types.h>//getpid  getppid头文件
int main()
{
    int i=0;
    pid_t pid;
    for(;i<3;i++)
    {
        printf("......%d\t",i);
    }
    printf("\n");
    pid=fork();
    if(pid>0)
    {
        printf("my is father process.pid=%d\n",getpid());
    }
      if(pid==0)
    {
        printf("my is son process.pid=%d\tppid=%d\n",getpid(),getppid());
    }
     for(i=0;i<3;i++)
    {
        printf("%d\t",i);
    }
    printf("\n");
    return 0;
}
huislee@huislee-virtual-machine:~/workspace/signal$
 gcc fork.c 
huislee@huislee-virtual-machine:~/workspace/signal$
 ./a.out 
......0 ......1 ......2
my is father process.pid=5239
0       1       2
my is son process.pid=5240       ppid=5239
0       1       2

如果出现以下执行结果

huislee@huislee-virtual-machine:~/workspace/signal$ ./a.out 
......0 ......1 ......2
my is father process.pid=5401
0       1       2
huislee@huislee-virtual-machine:~/workspace/signal$ my is son process.pid=5402      ppid=1
0       1       2

说明shell进程不知道a.out创建了子进程,shell检测到父进程执行完毕之后,Shell切换到了前台,导致出现这个现象。最简单的解决办法是在父进程中加sleep(1);
循环创建子进程:
在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 #include<sys/types.h>
int main()
{
    int i=0;
    pid_t pid;
    for(i=0;i<3;i++)
    {
         pid=fork();//此次如果不判断就会出现2的n次方个进程
        /* if(pid==0)
         {
         break;
         }*/
    }
   
    if(pid>0)
    {
        printf("my is father process.pid=%d\n",getpid());
    }
      if(pid==0)
    {
        printf("my is son process.pid=%d\tppid=%d\n",getpid(),getppid());
    }
    return 0;
}
不加if判断结果
huislee@huislee-virtual-machine:~/workspace/signal$
 ./a.out 
my is father process.pid=5534
my is father process.pid=5537
my is father process.pid=5535
my is father process.pid=5536
my is son process.pid=5538       ppid=1
my is son process.pid=5539       ppid=1
my is son process.pid=5540       ppid=1
my is son process.pid=5541       ppid=1

加if判断结果:
huislee@huislee-virtual-machine:~/workspace/signal$ ./a.out 
my is son process.pid=5561       ppid=5560
my is father process.pid=5560
my is son process.pid=5562       ppid=5560
my is son process.pid=5563       ppid=1

**

3.熟练掌握ps/kill命令

**
获取进程PID:ps aux 或 ps ajx
一般使用grep筛选:ps aux | grep “xxx”

[huislee@linuxprobe Desktop]$ ps a
   PID TTY      STAT   TIME COMMAND
  1132 tty1     Ss+    0:04 /usr/bin/Xorg :0 -background none -verbose -auth /ru
  3567 pts/0    Ss     0:00 /bin/bash
  3796 pts/0    R+     0:00 ps a
[huislee@linuxprobe Desktop]$ ps au
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root       1132  0.5  1.4 180276 28004 tty1     Ss+  14:16   0:04 /usr/bin/Xorg 
huislee    3567  0.0  0.1 116256  2908 pts/0    Ss   14:17   0:00 /bin/bash
huislee    3800  0.0  0.0 123356  1384 pts/0    R+   14:30   0:00 ps au
[huislee@linuxprobe Desktop]$ ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.4  0.4  53672  7616 ?        Ss   14:16   0:03 /usr/lib/syste
root          2  0.0  0.0      0     0 ?        S    14:16   0:00 [kthreadd]
root          3  0.0  0.0      0     0 ?        S    14:16   0:00 [ksoftirqd/0]
root          5  0.0  0.0      0     0 ?        S<   14:16   0:00 [kworker/0:0H]
root          7  0.0  0.0      0     0 ?        S    14:16   0:00 [migration/0]
root          8  0.0  0.0      0     0 ?        S    14:16   0:00 [rcu_bh]
root          9  0.0  0.0      0     0 ?        S    14:16   0:00 [rcuob/0]
root         10  0.0  0.0      0     0 ?        S    14:16   0:00 [rcuob/1]
root         11  0.0  0.0      0     0 ?        S    14:16   0:00 [rcuob/2]
root         12  0.0  0.0      0     0 ?        S    14:16   0:00 [rcuob/3]

查询信号并杀死:

[huislee@linuxprobe Desktop]$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	
[huislee@linuxprobe Desktop]$ kill -SIGKILL PID

进程间数据共享

在这里插入图片描述验证进程间是否共享全局变量

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 #include<sys/types.h>
int main()
{
    int i=0;
    int count=100;
    pid_t pid;
    for(i=0;i<3;i++)
    {
         pid=fork();
          if(pid==0)
         {
         break;
         }
    }
     if(i==0)
    {
        count+=100;
        printf("my is %d son process.pid=%d\tppid=%d\tcount=%d\n",i,getpid(),getppid(),count);
    }
      if(i==1)
    {
        count+=200;
        printf("my is %d son process.pid=%d\tppid=%d\tcount=%d\n",i,getpid(),getppid(),count);
    }
      if(i==2)
    {
        count=123;
        printf("my is %d son process.pid=%d\tppid=%d\tcount=%d\n",i,getpid(),getppid(),count);
    }
    if(i==3)
    {
        printf("my is father process.pid=%d\tcount=%d\n",getpid(),count);
    }
    
    return 0;
}
huislee@huislee-virtual-machine:~/workspace/signal$
 ./a.out 
my is 0 son process.pid=5725    ppid=5724       cou
nt=200
my is father process.pid=5724   count=100
my is 1 son process.pid=5726    ppid=5724       cou
nt=300
my is 2 son process.pid=5727    ppid=5724       cou
nt=123

说明:进程间不能共享全局变量,因为不能共享内存。

4.熟练掌握 execl/execlp函数,了解execl函数族

	exec函数族中,一般是由fork创建子进程后,在子进程中执行,也就是替换子进程中的东西,进程中的空间代码完全被新程序代替,但是调用exec程序不会创建新进程,进程ID也没有发生变化。

函数原型:
**#include <unistd.h>
extern char **environ;
int execl(const char path, const char arg, …);
path:要执行的程序的绝对路莅变参
arg:要执行的程序的需要的参数
第一arg:占位
后边的arg:命令的参数
参数写完之后:NULL
一般执行自己写的程序
**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 argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char const argv[], char const envp[]);
l代表的是list:命令行参数列表
p代表的是path:搜索file时的使用的path变量
v代表的是vector:使用命令行参数数组
e代表的是environment:使用环境变量数组

在这里插入图片描述

5.孤儿进程、僵尸进程

孤儿进程、僵尸进程参考链接:https://blog.csdn.net/Eunice_fan1207/article/details/81387417
每个进程的产生都有自己的唯一的ID号(pid),并且附带有一个它父进程的ID号(ppid)。进程死亡时,ID被回收。
进程间靠优先级获得CPU资源,时间片段轮换来更新优先级,以保证不会一个进程占据CPU时间过长。每个进程都得到轮换运行,因为这个时间非常短,所以给我们就好像是系统在同时运行好多进程。
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

子进程死亡需要父进程来处理,那么意味着正常的进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没父进程处理,这个死亡的子进程就是孤儿进程。

但孤儿进程与僵尸进程不同的是,由于父进程已经死亡,系统会帮助父进程回收处理孤儿进程。所以孤儿进程实际上是不占用资源的,因为它终究是被系统回收了。不会像僵尸进程那样占用ID,损害运行系统。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 #include<sys/types.h>
 #include<stdlib.h>

int main()
{
	pid_t pid=fork();
 
	if(pid==0)
	{
		printf("child ppid is %d\n",getppid());
		sleep(5);     //为了让父进程先结束
		printf("child ppid is %d\n",getppid());
	}
	else
	{
		printf("parent id is %d\n",getpid());
	}
 
	exit(0);
    return 0;
}

huislee@huislee-virtual-machine:~/workspace/signal$ ./a.out 
parent id is 5971
child ppid is 5971
huislee@huislee-virtual-machine:~/workspace/signal$ child ppid is 1

从执行结果来看,此时由pid ==5971的父进程创建的子进程,其输出的父进程pid == 1,说明当其为孤儿进程时被init进程回收,最终并不会占用资源,这就是为什么要将孤儿进程分配给init进程。
子进程先于父进程退出后,子进程的PCB需要其父进程释放,但是父进程并没有释放子进程的PCB,这样的子进程就称为僵尸进程,僵尸进程实际上是一个已经死掉的进程。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
 
int main()
{
	pid_t pid=fork();
 
	if(pid==0)  //子进程
	{
     	printf("child id is %d\n",getpid());
		printf("parent id is %d\n",getppid());
	}
	else  //父进程不退出,使子进程成为僵尸进程
	{
        while(1)
		{}
	}
	exit(0);
    return 0;
}

huislee@huislee-virtual-machine:~/workspace/signal$ ./a.out 
child id is 6049
parent id is 6048
huislee@huislee-virtual-machine:~$ ps aux | grep 6049
huislee    6049  0.0  0.0      0     0 pts/0    Z+   16:22   0:00 [a.out] <defunct>
huislee    6051  0.0  0.0  16180  1092 pts/1    S+   16:22   0:00 grep --color=auto 6049

用ps可以看到子进程后有一个<defunct> ,defunct是已死的,僵尸的意思,可以看出这时的子进程已经是一个僵尸进程了。因为子进程已经结束,而其父进程并未释放其PCB,所以产生了这个僵尸进程。
一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。这个僵尸进程需要它的父进程来为它收尸,如果他的父进程没有处理这个僵尸进程的措施,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。

在实际编程中,避免和防范僵尸进程的产生显得尤为重要。
僵尸进程处理方式
任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“defunct”。如果父进程能及时处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。所以孤儿进程不会占资源,僵尸进程会占用资源危害系统。我们应当避免僵尸进程的出现。

解决方式如下:

1):一种比较暴力的做法是将其父进程杀死,那么它的子进程,即僵尸进程会变成孤儿进程,由系统来回收。但是这种做法在大多数情况下都是不可取的,如父进程是一个服务器程序,如果为了回收其子进程的资源,而杀死服务器程序,那么将导致整个服务器崩溃,得不偿失。显然这种回收进程的方式是不可取的,但其也有一定的存在意义。

2):SIGCHLD信号处理

我们都知道wait函数是用来处理僵尸进程的,但是进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。我们先来看看wait函数的定义

#include <sys/types.h> /* 提供类型pid_t的定义,实际就是int型 */

#include <sys/wait.h>

pid_t wait(int *status)

参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:pid=wait(NULL);如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。

由于调用wait之后,就必须阻塞,直到有子进程结束,所以,这样来说是非常不高效的,我们的父进程难道要一直等待你子进程完成,最后才能执行自己的代码吗?难道就不能我父进程执行自己的代码,你子进程什么时候完成我就什么时候去处理你,不用一直等你?当然是有这种方式了。

实际上当子进程终止时,内核就会向它的父进程发送一个SIGCHLD信号,父进程可以选择忽略该信号,也可以提供一个接收到信号以后的处理函数。对于这种信号的系统默认动作是忽略它。我们不希望有过多的僵尸进程产生,所以当父进程接收到SIGCHLD信号后就应该调用 wait 或 waitpid 函数对子进程进行善后处理,释放子进程占用的资源。
处理僵尸进程的简单的例子:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>
 
void deal_child(int num)
{
	printf("deal_child into\n");
	wait(NULL);
}
 
int main()
{
	signal(SIGCHLD,deal_child);
	pid_t pid=fork();
	int i;
 
	if(pid==0)
	{
		printf("child is running\n");
		sleep(2);
		printf("child will end\n");
	}
	else
	{
		sleep(1);   //让子进程先执行
		printf("parent is running\n");
		sleep(10);    //一旦被打断就不能再进入睡眠
		printf("sleep 10 s over\n");
		sleep(5);
		printf("sleep 5s over\n");
	}
 
	exit(0);
}
huislee@huislee-virtual-machine:~/workspace/signal$
 ./a.out 
child is running
parent is running
child will end
deal_child into
sleep 10 s over
sleep 5s over

signal函数(不是阻塞函数)

signal(参数1,参数2);

参数1:我们要进行处理的信号。系统的信号我们可以再终端键入 kill -l查看(共64个)。其实这些信号是系统定义的宏。

参数2:我们处理的方式(是系统默认还是忽略还是捕获)。

eg: signal(SIGINT ,SIG_ING ); //SIG_ING 代表忽略SIGINT信号

eg:signal(SIGINT,SIG_DFL); //SIGINT信号代表由InterruptKey产生,通常是CTRL +C或者是DELETE。发送给所有ForeGroundGroup的进程。 SIG_DFL代表执行系统默认操作,其实对于大多数信号的系统默认动作是终止该进程。这与不写此处理函数是一样的。

我们也可以给参数2传递一个信号处理函数的地址,但是这个信号处理函数需要其返回值为void,并且默认自带一个int类型参数

这个int就是你所传递的第一个信号参数的值(你用kill -l可以查看)

我们测试了一下,如果创建了5个子进程,但是销毁的时候仍然有两个仍是僵尸进程,这又是为什么呢?

这是因为当5个进程同时终止的时候,内核都会向父进程发送SIGCHLD信号,而父进程此时有可能仍然处于信号处理的deal_child函数中,那么在处理完之前,中间接收到的SIGCHLD信号就会丢失,内核并没有使用队列等方式来存储同一种信号

所以为了解决这一问题,我们需要调用waitpid函数来清理子进程。

void deal_child(int sig_no)
 
{
 
    for (;;) {
 
        if (waitpid(-1, NULL, WNOHANG) == 0)
 
            break;
 
    }  
 
}

只有检验没有僵尸进程,他才会返回0,这样就可以确保所有的僵尸进程都被杀死了。

6.熟练掌握wait函数

wait函数实现进程的回收。
pid_t wait(int* status);
返回值:-1:回收失败,已经没有子进程了 ,>0:回收是子进程对应的pid
参数:status  	判断子进程是如何死的
正常退出      被某个信号杀死了
每调用一次只能四收一个子进程

在这里插入图片描述在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 #include<sys/types.h>
 #include<wait.h>
int main()
{
    int i=0;
    pid_t pid;
    for(;i<3;i++)
    {
        printf("......%d\t",i);
    }
    printf("\n");
         pid=fork();
   
    if(pid>0)
    {
        printf("my is father process.pid=%d\n",getpid());
        int status;
        pid_t wpid=wait(&status);
        //判断是否正常退出
        if(WIFEXITED(status))
        {
            printf("exit value :%d\n",WEXITSTATUS(status));
        }
        //判断是否被信号杀死
        if(WIFSIGNALED(status))
        {
            printf("exit by signal:%d\n",WTERMSIG(status));
        }
        printf("died child pid=%d\n",wpid);
    }
      if(pid==0)
    {
        sleep(2);
        printf("my is sonprocess.pid=%d\tppid=%d\n",getpid(),getppid());
    }
     for(i=0;i<3;i++)
    {
        printf("%d\t",i);
    }
    printf("\n");
    return 0;
}
huislee@huislee-virtual-machine:~/workspace/signal$ ./a.out 
......0 ......1 ......2
my is father process.pid=6340
my is sonprocess.pid=6341       ppid=6340
0       1       2
exit value :0
died child pid=6341
0       1       2

父子进程使用文件进行通信

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<fcntl.h>
 #include<wait.h>
 #include<stdlib.h>
 #include<sys/stat.h>

 //操作终端文件 /dev/tty默认阻塞
 int main(int argc,char* argv[])
 {
     int fd=open("temp",O_CREAT  |  O_RDWR,0664);
    if(fd==-1)
    {
        perror("open error");
        exit(1);
    }
    pid_t pid=fork();
    if(pid==-1)
    {
        perror("fork error");
        exit(1);
    }
    if(pid>0)
    {
        char* p="软件开发,linux学习";
        write(fd,p,strlen(p)+1);
        close(fd);
    }else if(pid==0)
    {
        sleep(1);
        char buf[1024];
        lseek(fd,0,SEEK_SET);
        int len=read(fd,buf,sizeof(buf));
        printf("%s\n",buf);
        close(fd);
    }
    
    return 0;
 }
huislee@huislee-virtual-machine:~/workspace/signal$ 软件开发,linux学习
^C
huislee@huislee-virtual-machine:~/workspace/signal$ cat temp 
软件开发,linux学习

7.熟练掌握 waitpid函数

//waitpid
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include<sys/stat.h>
#include<string.h>
 #include<wait.h>
 #include<stdlib.h>


 int main(int argc,char* argv[])
 {

    int i=0,num=3;
    pid_t pid;
    for(i=0;i<num;i++)
    {
         pid=fork();
          if(pid==0)
         {
         break;
         }
    }
    if(i==0)
    {
        execlp("ps","ps","aux",NULL);
        perror("execlp ps");
        exit(1);
    }else  if(i==1)
    {
        execl("a.out","a.out",NULL);
        perror("execlp a.out");
        exit(1);
    }else  if(i==2)
    {
        execl("./error","error",NULL);
        perror("execlp error");
        exit(1);
    }else if(i==num)
    {
        int status;
        pid_t wpid;
        while((wpid=wait(&status))!=-1)
        // while((wpid=waitpid(-1,&status,WNOHANG))!=-1)
        {
            if(wpid==0)
            {
                continue;
            }
            printf(".......child died pid=%d\n",wpid);
            if(WIFEXITED(status))
            {
                printf("return value %d\n",WEXITSTATUS(status));
            }
            else if(WIFSIGNALED(status))
            {
                printf("died by signal:%d\n",WTERMSIG(status));
            }
        }
    }
    return 0;
 }
huislee@huislee-virtual-machine:~/workspace/signal$ gcc multi_process.c -o a
huislee@huislee-virtual-machine:~/workspace/signal$ ./a
execlp error: No such file or directory
.......child died pid=7875
return value 1
.......child died pid=7874
return value 0
   PID TTY          TIME CMD
  3643 pts/0    00:00:00 bash
  7872 pts/0    00:00:00 a
  7873 pts/0    00:00:00 ps
  7876 pts/0    00:00:00 a.out
.......child died pid=7873
return value 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值