在Linux系统中,进程的生命周期内主要包含:进程就绪、进程执行、进程等待和进程退出。
就绪转执行
处于就绪状态的进程,当进程调度程序为之分配了处理机(CPU)后,该进程便由就绪状态转变成执行状态。
执行转就绪
处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完或更高优先级的进程抢占而不得不让出处理机,于是进程从执行状态转变成就绪状态。
执行转等待
正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成等待状态。
等待转就绪
处于阻塞状态的进程,若其等待的事件已经发生,于是进程由等待状态转变为就绪状态。
执行转退出
进程执行完毕,撤销而退出。
其中,进程等待是进程控制的关键,也是本关的重点。
进程控制块(PCB)是进程在整个运行过程中非常重要的一个数据结构,里面包含以下几种信息:
进程终止或者退出的时候,进程会关闭所有文件描述符,释放用户空间分配的内存,但是PCB却会暂时保留。假如进程正常终止,PCB里面就记录进程的退出状态;如果是异常终止,那么PCB里面存放着导致该进程终止的信号。
子进程的退出状态必须由父进程回收,也就是说,父进程必须得等待子进程退出后再自己退出,否则子进程会变成僵尸进程(没有任何可执行代码,不会被调度,只有一个进程描述符用来记录退出的状态,除此之外不再占用其他任何资源)。
#include
#include
pid_t wait(int* status);
参数:status
,整型指针,指向的地址即存放退出子进程的退出状态,不关心可以设为NULL
。
等待方式是阻塞式等待,一旦子进程退出,父进程就会立刻收到SIGCHLD
信号。
注意:父进程调用wait
,是等待任意一个已经退出的子进程,只要是有子进程退出了,那么就获取子进程退出状态然后返回。
#include
#include
pid_t waitpid( pid_t pid, int *status ,int options);
参数详解:
pid
:希望等待退出的子进程的进程号;
status
:整型指针,指向的地址即存放退出子进程的推出状态,不关心可以设为NULL
;
options
:设置为0,代表阻塞式等待,如果设置为WNOHANG
,waitpid
发现没有已经退出的子进程可以收集,就返回0
,此时是非阻塞式等待。
返回值:
返回0
表示没有已经退出的子进程;返回正值,表示有已经退出的子进程。
试想这样的场景:
你和你的树懒一起到外面吃午餐,你吃的比较快,但是要等待树懒吃完后才能一起走。
整个过程如下:
以进程等待代替整个过程, 对于上述过程可以理解为创建子进程->等待子进程退出->主进程退出。
本关任务:
在主函数的最开始会初始化一个全部变量g_i4event
为0
。
本关的编程任务是补全右侧代码片段中两段Begin
至End
中间的代码,具体要求如下:
创建子进程,创建完后,将g_i4event
置为1
;
子进程等待3s,然后子进程退出;
父进程等待一秒,将g_i4event
置为2
;然后等待子进程退出,父进程获取子进程退出的状态后将g_i4event
置为3
;
process_wait
采用wait
函数,process_waitpid
采用waitpid
函数。
测试样例:
测试输入:1
预期输出:You and Sloth go to have lunch!
You have finished your meal!You need wait the sloth
Sloth have finished your meal! You and sloth will go home.
测试输入:2
预期输出:You and Sloth go to have lunch!
You have finished your meal!You need wait the sloth
Sloth have finished your meal! You and sloth will go home.
测试说明
测试过程:
用户补全框架内的代码,实现功能性代码;
接着根据程序的输出判断程序是否正确。
不要在代码中使用printf
等进行输出,以免引起结果判断错误。
#include
#include
#include
#include
#include
#include
#include
#include
#include
pthread_t pid;
int g_i4event = 0;
int process_wait(void);
int process_waitpid(void);
int g_i4event;
int process_wait(void)
{
/********Begin********/
int rc = fork();
g_i4event=1;
if(rc==0)
{
sleep(3);
}
else
{
sleep(1);
g_i4event=2;
wait(NULL);
g_i4event=3;
}
return 0;
/*********End*********/
}
int process_waitpid(void)
{
/********Begin********/
int rc = fork();
g_i4event=1;
if(rc==0)
{
sleep(3);
}
else
{
sleep(1);
g_i4event=2;
waitpid(rc,NULL,0);
g_i4event=3;
}
return 0;
/*********End*********/
}
void *detect(void *arg)
{
int count = 0;
while (1)
{
switch(g_i4event)
{
case 0:
break;
case 1:
count ++;
printf("You and Sloth go to have lunch!\n");
break;
case 2:
count ++;
if(2 == count)
{
printf("You have finished your meal!You need wait the sloth\n");
}
else
{
printf("You have not finished your meal!\n");
return NULL;
}
break;
case 3:
count ++;
if(3 == count)
{
printf("Sloth have finished your meal! You and sloth will go home.\n");
}
else
{
printf("Sloth have not finished your meal!\n");
}
return NULL;
default:
break;
}
g_i4event = 0;
usleep(10 * 1000);
}
return NULL;
}
#define WAITCMD 1
#define WAITPIDCMD 2
int main(int argc, char *argv[])
{
char cmd[32] = {0};
scanf("%s", cmd);
pthread_create(&pid, NULL, detect, NULL);
if(WAITCMD == atoi(cmd))
{
process_wait ();
}
else if(WAITPIDCMD == atoi(cmd))
{
process_waitpid ();
}
pthread_join(pid, NULL);
return 0;
}