临沂网站定制免费域名注册免费空间

当前位置: 首页 > news >正文

临沂网站定制,免费域名注册免费空间,男科医院网站建设,网页生成pdf失败文章目录 进程等待进程等待必要性实验(见见猪跑)进程等待的方法wait方法waitpid方法宏的使用方法获取子进程status 阻塞VS非阻塞概念对比非阻塞有什么好处 具体代码实现进程的阻塞等待方式:进程的非阻塞等待方式:让父进程做其他任务 进程等待 进程等待必要性 之前讲过子进程退出父进程如果不管不顾就可能造成‘僵尸进程’的问题进而造成内存泄漏。另外进程一旦变成僵尸状态那就刀枪不入“杀人不眨眼”的kill -9 也无能为力因为谁也没有办法杀死一个已经死去的进程。最后父进程派给子进程的任务完成的如何我们需要知道。如子进程运行完成结果对还是不对,或者是否正常退出。父进程通过进程等待的方式回收子进程资源获取子进程退出信息 因此,进程等待是为了: 避免内存泄漏获取子进程执行的结果 代码跑完,结果对-退出码代码跑完,结果不对-退出码代码运行异常-信号
等待就是通过系统调用,获取子进程退出码或者退出信号的方式,顺便释放内存 实验(见见猪跑) #includesys/types.h
#includesys/wait.h
int main() {pid_t id fork();if(id 0){int cnt 10;while(cnt){printf(我是子进程:%d,父进程:%d,cnt:%d\n,getpid(),getppid(),cnt–);}exit(10);//此时都是S状态}//此时子进程变成Z状态sleep(15);pid_t ret wait(NULL);//回收子进程if(id 0){printf(wait success:%d\n,ret);}sleep(5);//父进程退出 }waitpid用法; #includesys/types.h
#includesys/wait.h
int main() {pid_t id fork();if(id 0)//子进程返回0父进程返回子进程id{int cnt 10;while(cnt){printf(我是子进程:%d,父进程:%d,cnt:%d\n,getpid(),getppid(),cnt–);}exit(10);//退出的三种结果://1.代码跑完,结果是对的//2.代码跑完,结果是错的//3.代码没有跑完,出异常了//此时都是S状态}//此时子进程变成Z状态sleep(15);int status 0;pid_t ret waitpid(id,status,0);//回收子进程//错误观念:此时status的值变成了10//因为status不是被整体使用的,有自己的位图结构if(id 0){printf(wait success:%d,sig number:%d,child exit code:%d\n,ret,status 0x7F,(status8)0xFF);}//sig number:0 child exit code:10sleep(5);//父进程退出 }监控脚本 ps ajx | head -1 ps axj | grep mytest | grep -v grep 第一句话是把标题拿出来 第二句话是把matest的进程信息拿出来 第三句话是把grep本身的进程信息去掉 之后写一个循环语句 while :; do ps ajx | head -1 ps axj | grep mytest | grep -v grep; sleep 1; done(ctrl z 退出) 进程等待的方法 wait方法 :!man 2 wait //可以查看到相关wait的用法信息 需要包含两个头文件 #includesys/types.h
#includesys/wait.h
pidt wait(int* status);
返回值
成功返回被等待进程pid失败返回-1。
参数
输出型参数获取子进程退出状态,不关心则可以设置成为NULLwaitpid方法 pid
t waitpid(pid_t pid, int *status, int options);
返回值
当正常返回的时候waitpid返回收集到的子进程的进程ID
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在
参数 pid Pid-1,等待任一个子进程。与wait等效。 Pid0.等待其进程ID与pid相等的子进程。 status: WIFEXITED(status): 若为正常终止子进程返回的状态则为真。查看进程是否是正常退出 WEXITSTATUS(status): 若WIFEXITED非零提取子进程退出码。查看进程的退出码 options: WNOHANG: 若pid指定的子进程没有结束则waitpid()函数返回0不予以等待。若正常结束则返回该子进程的ID。这里有一个问题: status按理来说是会返回信号退出码的,但是一个整数怎么能返回两个整数呢? 所以我们不应该吧status当作一个完整的整数,而是应该看作位图结构(后面会详解) 宏的使用方法 int ret waitpid(id,status,0) if(ret 0) {//是否正常退出if(WIFEXITED(status)){//判断子进程运行结果是否OKprintf(exit code :%d\n,WEXITSTATUS(status));}else//出异常了(比如kill -9){//TODOprintf(child exit not normal\n);} }如果子进程已经退出调用wait/waitpid时wait/waitpid会立即返回并且释放资源获得子进程退出信息。如果在任意时刻调用wait/waitpid子进程存在且正常运行则进程可能阻塞。如果不存在该子进程则立即出错返回。
获取子进程status wait和waitpid都有一个status参数该参数是一个输出型参数由操作系统填充。 如果传递NULL表示不关心子进程的退出状态信息。 否则操作系统会根据该参数将子进程的退出信息反馈给父进程。 status不能简单的当作整形来看待可以当作位图来看待具体细节如下图本身是32位,但是这里我们只研究status低16比特位 1.代码跑完,结果是对的 2.代码跑完,结果是错的 3.代码没有跑完,出异常了 终止信号(即退出码)用来表示是否正常结束(为0则表示正常退出) 用退出状态表示结果是否正确(通过kill -l进行对应数字的查看(比如发生段错误,除0操作等)),此时退出码是否为0或者是其他的,都无意义,我们不讨论它. 第七位是信号编号
获取退出状态: (status8)0xFF ) 获取终止信号: (status 0x7F)) #includesys/types.h #includestdio.h #includesys/wait.h
int main() {pid_t id fork();if (id 0){int cnt 10;while (cnt){printf(我是子进程:%d,父进程:%d,cnt:%d\n, getpid(), getppid(), cnt–);sleep(1);}}int status 0;//1.让OS释放子进程的僵尸状态//2.获取子进程的退出结果//3.在等待期间,子进程没有退出的时候,父进程只能阻塞等待.pid_t ret waitpid(id, status, 0);if (id 0){printf(wait success: %d,sig number : %d ,child exit code: %d\n,ret,(status 0x7F),(status8)0xFF );}}测试代码
#include sys/wait.h
#include stdio.h
#include stdlib.h
#include string.h
#include errno.h
int main( void ) { pid_t pid; if ( (pidfork()) -1 ) perror(fork),exit(1); if ( pid 0 ){ sleep(20); exit(10); } else { int st; int ret wait(st); if ( ret 0 ( st 0X7F ) 0 ){ // 正常退出 printf(child exit code:%d\n, (st8)0XFF); } else if( ret 0 ) { // 异常退出 printf(sig code : %d\n, st0X7F ); } }
}
测试结果 [rootlocalhost linux]# ./a.out #等20秒退出 child exit code:10 [rootlocalhost linux]# ./a.out #在其他终端kill掉 sig code : 9等待的本质 监测子进程退出的信息 并且将子进程退出信息通过status拿回来 这个信息exit code signal在子进程的PCB中 再谈进程退出: 1.进程退出会变成僵尸进程-会把自己的退出结果写到自己的task_struct 2.wait/waitpid是一个系统调用-OS-OS有资格也有能力去读取子进程的task_struct 阻塞VS非阻塞 概念对比 例子: 1.不挂电话,监测李四的状态-阻塞 2.张三-李四,本质是状态检测,如果没有就绪,直接返回-每一次都是一次非阻塞等待-多次非阻塞等待我们称为:轮询 打电话-系统调用wait/waitpid 张三-父进程 李四-子进程 我们上面写的代码都是阻塞等待 轮询等待: #includesys/types.h #includestdio.h #includesys/wait.h
int main() {pid_t id fork();if (id 0){int cnt 10;while (cnt){printf(我是子进程:%d,父进程:%d,cnt:%d\n, getpid(), getppid(), cnt–);sleep(1);}}int status 0;while(1)//这是一个死循环作为轮询等待的一个条件{pid_t ret waitpid(id, status, WNOHANG);//wnohang非阻塞子进程没有退出时父进程监测之后立即返回//如果没有设置WNOHANG,则会卡在这一步,除非子进程退出,或者你的id值设置得有问题.否则不会执行下面的代码if(ret 0)//设置了WNOHANG才会可能出现返回值为0的情况{//waitpid调用成功子进程没有退出,我的waitpid没有等待失败//仅仅是监测到了子进程没有退出printf(wait done,but child is running\n,);}else if(ret 0){//1.waitpid调用成功等待成功子进程退出了 printf(wait success: %d,sig number : %d ,child exit code: %d\n,ret,(status 0x7F),(status8)0xFF );break;}else{//waitpid调用失败返回值为-1//eg.传入的id参数传错了printf(waitpid call failed\n);break;}sleep(1);} }非阻塞有什么好处 不会占用父进程的所有精力,可以在轮询期间干干其他的 [[指针进阶]] [[typedef函数进阶]] #include stdio.h #include string.h #include unistd.h #include sys/types.h #include sys/wait.h #include assert.h #include stdlib.h#define TASK_NUM 10typedef void (*func_t)(); func_t other_task[TASK_NUM] {NULL};void sync_disk() {printf(这是一个刷新磁盘的任务\n); } void sync_log() {printf(这是一个同步日志的任务\n); } void net_send() {printf(这是一个网络发送的任务\n); }void LoadTask(func_t func) {for (int i 0; i TASK_NUM; i){if (other_task[i] NULL){other_task[i] func;break;}} }void InitTask() {for (int i 0; i TASK_NUM; i)other_task[i] NULL;LoadTask(sync_disk);LoadTask(sync_log);LoadTask(net_send); }void RunTask() {for (int i 0; i TASK_NUM; i){if (other_task[i] NULL)continue;other_taski;} }int main() {pid_t id fork();assert(id 0);if (id 0){int cnt 5;while (cnt){printf(我是子进程我的pid是%d我的ppid是%d我还有%dS存活\n, getpid(), getppid(), cnt–);sleep(1);}printf(我已经退出\n);exit(11);}InitTask();while (1){sleep(1);int status;pid_t ret_id waitpid(id, status, WNOHANG);if (ret_id 0){printf(我是父进程,我已经回收子进程,ret_id是%d,退出码为%d,退出信号为%d\n, ret_id, (status 8) 0xFF, status 0x7F);exit(0);}else if (ret_id 0){RunTask();continue;}else{printf(调用出错\n);}} } 具体代码实现 进程的阻塞等待方式: #define _CRT_SECURE_NO_WARNINGS 1 int main() {pid_t pid;pid fork();if (pid 0) {printf(%s fork error\n, FUNCTION);return 1;}else if (pid 0) { //childprintf(child is run, pid is : %d\n, getpid());sleep(5);exit(257);}else {int status 0;pid_t ret waitpid(-1, status, 0);//阻塞式等待等待5Sprintf(this is test for wait\n);if (WIFEXITED(status) ret pid) {printf(wait child 5s success, child return code is :%d.\n, WEXITSTATUS(status));}else {printf(wait child failed, return.\n);return 1;}}return 0; } 运行结果: [rootlocalhost linux] # . / a.out child is run, pid is : 45110 this is test for wait wait child 5s success, child return code is : 1.进程的非阻塞等待方式: #include stdio.h #include unistd.h #include stdlib.h #include sys/wait.h int main() {pid_t pid;pid fork();if (pid 0) {printf(%s fork error\n, FUNCTION);return 1;}else if (pid 0) { //childprintf(child is run, pid is : %d\n, getpid());sleep(5);exit(1);}else {int status 0;pid_t ret 0;do{ret waitpid(-1, status, WNOHANG);//非阻塞式等待-子进程没有退出,父进程检测时候,立即返回if (ret 0) {//子进程没有退出,我的waitpid没有等待失败//仅仅是监测到了子进程没有退出printf(child is running\n);}sleep(1);} while (ret 0);if (WIFEXITED(status) ret pid) {printf(wait child 5s success, child return code is :%d.\n, WEXITSTATUS(status));}else {printf(wait child failed, return.\n);return 1;}}return 0; }让父进程做其他任务 #include stdio.h #include unistd.h #include stdlib.h #include string.h #include sys/types.h #include sys/wait.h#define TASK_NUM 10// 要保存的任务相关的 typedef void (*func_t)(); //? func_t other_task[TASK_NUM] {NULL}; //函数指针数组// 预设一批任务 void sync_disk() {printf(这是一个刷新数据的任务!\n); } void sync_log() {printf(这是一个同步日志的任务!\n); } void net_send() {printf(这是一个进行网络发送的任务!\n); }//将任务加载进任务列表 int LoadTask(func_t func) {int i 0;for(; i TASK_NUM; i){if(other_task[i] NULL) break;}if(i TASK_NUM) return -1;else other_task[i] func;return 0; }void InitTask() {for(int i 0; i TASK_NUM; i) other_task[i] NULL;LoadTask(sync_disk);LoadTask(sync_log);LoadTask(net_send); }void RunTask() {for(int i 0; i TASK_NUM; i){if(other_task[i] NULL) continue;other_taski;} }int main() {pid_t id fork();if(id 0){//子进程int cnt 50;while(cnt){printf(我是子进程我还活着呢我还有%dS, pid: %d, ppid%d\n, cnt–, getpid(), getppid());sleep(1);//int *p NULL;//*p 100;}exit(111);}InitTask();// 父进程//pid_t ret_id wait(NULL);while(1){int status 0;pid_t ret_id waitpid(id, status, WNOHANG); // 夯住了if(ret_id 0){printf(waitpid error!\n);exit(1);}else if(ret_id 0){RunTask();sleep(1);continue;}else{if(WIFEXITED(status)) // 是否收到信号{printf(wait success, child exit code: %d\n, WEXITSTATUS(status));}else{printf(wait success, child exit signal: %d\n, status 0x7F);}// printf(我是父进程等待子进程成功, pid: %d, ppid: %d, ret_id: %d, child exit code: %d, child exit signal: %d\n,\// getpid(), getppid(), ret_id, (status8)0xFF, status 0x7F);break;}}