进程终止,进程等待

进程终止:

进程退出的场景:

  • 代码运行完毕,结果正常
  • 代码运行完毕,结果不正常
  • 代码异常终止

进程常见的退出方式:

1.正常终止:

  • 从main()函数返回
  • 调用exit
  • _exit

正常终止,可以通过echo $?来查看进程的退出码

2.异常退出:

  • ctrl+c,信号终止

 

代码执行完后,如何得到代码退出的场景?

根据程序的退出码,不能根据函数的返回值

exit函数与_exit函数:

1._exit函数:

#include<unistd.h>
void _exit(int status);

参数:status定义了进程的终止状态,父进程通过wait来获取该值。虽然status是int,但是仅有低8为可以被父进程所用,所以_exit(-1)时,在中断执行$?发现返回值时255

2.exit函数:

#include<unistd.h>
void exit(int status);

3.exit函数和_exit函数有什么区别?

  • exit最后也会调用_exit或on_exit定义的清理函数,但是exit还做了一些其他工作
  • 执行用户定义的清理函数(atexit/on_exit)
  • 关闭所有打开的流,所有的缓存数据均被写入
  • 调用_exit

实例:

exit:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 int main()
  4 {
  5     printf("haha");
  6     exit(0);    
  7 }

运行结果:

 _exit:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3
  4 int main()
  5 {
  6     printf("haha");
  7     _exit(0);
  8 }

证明了exit清空了缓冲区,而_eixt是强制中止,并没有清空缓冲区,释放内存

return退出:

return是一种更常见的退出进程的方式,执行return n等于执行exit(n),因为调用main的运行时函数会将main的返回值最为exit的参数

 

进程等待: 

进程等待的必要性:

  • 子进程退出,父进程如果不管不顾,就会造成僵尸进程的问题,进而导致内存泄漏
  • 另外,进程一旦变成了僵尸状态,就会刀枪不入,即使杀人不眨眼的kill -9也无能为力。因为谁也没有能力杀死一个已经死了的进程
  • 最后,父进程派给子进程的任务完成的如何,我们需要知道,子进程运行完,是否正常退出?结果是对还是不对?
  • 父进程通过进程等待的方式回收子进程资源。获取子进程的退出信息

进程等待的方法:

wait函数:

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *status);

返回值:成功返回被等待进程的pid,失败返回-1

参数:输出型参数,获取子进程退出状态,终止进程的终止状态就放在他所指的内存单元里。如果不关心终止状态,则可以设置为NULL。

  • wait函数,子进程未退出时,父进程将会被阻塞,直到子进程退出,wait()返回,父进程才能继续运行。而waipid()有一个选项可以使调用者非阻塞等待
  • wait函数会默认等待任意子进程,但是waitpid可以等待指定的子进程

每个进程都是独立的,父进程怎么拿到子进程的信息的?

wait函数时系统调用,系统调用后并拷贝一份给父进程

waitpid函数:

#include<sys/types.h>
#include<sys/wait.h>

pid_t waitpid(pid_t pid,int *status,int options);

返回值:

  • 正常返回:返回收集到的子进程的进程id
  • 如果设置了WNOHANG,而调用中waitpid发现自己没有已退出的子进程可回收,返回0
  • 如果调用中出错,返回-1,这时errno会被设置成对应的值以指示错误所在

参数:

pid:

  • pid=-1,等待任何一个子进程,与wait等效
  • pid>0,等待其进程id与pid相等的子进程

status:

  • WIFEXITED(status):查看进程是否正常退出,若正常终止子进程的返回的状态,则为真
  • WEXITSTATUS(status):查看进程的退出码,若WIFEXITED非0,提取子进程退出码

options:

  • WNOHANG:(等待时不要阻塞)若pid指定的子进程还没有结束,则waitpid()返回0,不予以等待,若正常结束,则返回该子进程的ID

wait/waitpid等待的方式:

  • 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程的退出信息
  • 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
  • 如果不存在该子进程,则立即出错返回

获取子进程stutas:

  • wait/waitpid,都有一个参数status参数,该参数是一个输出型参数,由操作系统填充
  • 如果传递NULL,表示不关心子进程的退出状态信息
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程
  • status不能简单的当作参数来看待,他可以当作一个位图(这里只研究团队低16位)

阻塞式等待:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>
  6 
  7 int main()
  8 {
  9     pid_t pid;
 10     pid = fork();
 11     if(pid<0)
 12     {
 13         perror("fork");
 14         return 1;
 15     }
 16     else if(pid==0)
 17     {
 18         printf("child is run,pid is:%d\n",getpid());
 19         sleep(5);
 20         exit(257);
 21     }
 22     else
 23     {
 24         int status = 0;
 25         pid_t ret = waitpid(-1,&status,0);//等待任意进程,阻塞式
 26         printf("this is test for wait\n");
 27         if(WIFEXITED(status)&&ret == pid)//查看进程是否正常退出
 28         {
 29             printf("wiat child 5s success,child return code is:%d\n",
                /WEXITSTATUS(status));//正常,查看退出码
 30         }
 31         else
 32         {
 33             printf("wait child failed,return.\n");
 34             return 1;
 35         }
 36     }
 37     return 0;
 38 }

运行结果:

 

非阻塞式等待

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>

  7 int main()
  8 {
  9     pid_t pid;
 10     pid = fork();
 11     if(pid<0)
 12     {
 13         perror("fork");
 14         return 1;
 15     }
 16     else if(pid==0)
 17     {
 18         printf("child is run,pid is:%d\n",getpid());
 19         sleep(5);
 20         exit(1);
 21     }
 22     else
 23     {
 24         int status = 0;
 25         pid_t ret = 0;
 26         do
 27         {
 28             ret = waitpid(-1,&status,WNOHANG);//阻塞式等待,轮询
 29             if(ret ==0)
 30             {
 31                 printf("child is running\n");
 32             }
 33             sleep(1);
 34         }while(ret==0);
 35         if(WIFEXITED(status)&&ret == pid)
 36         {
 37             printf("wiat child 5s success,child return code is:%d\n",
                        /WEXITSTATUS(status));
 38         }
 39         else
 40         {
 41             printf("wait child failed,return.\n");
 42             return 1;
 43         }
 44     }
 45     return 0;
 46 }

运行结果如下: 

 

阻塞式等待需要用轮询的方式,定期查看子进程的状态.

阻塞式等待可能失败,

返回值ret=0,表示子进程还在运行,父进程干其他的事 ;

>0,表示等待成功,子进程返回

<0,等待失败

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值