明星个人网站建设方案国内产品推广网站

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

明星个人网站建设方案,国内产品推广网站,北京建设安全协会网站,北京网站建设哪家比较好文章目录 1. 为什么要进程等待2. 进程等待的方法waitwaitpid非阻塞轮询 1. 为什么要进程等待 子进程退出#xff0c;如果父进程还未结束#xff0c;没有管这个子进程#xff0c;那么就可能会造成“僵尸进程”问题#xff0c;进而出现内存泄漏 如果这个进程变成了“僵尸进程… 文章目录 1. 为什么要进程等待2. 进程等待的方法waitwaitpid非阻塞轮询 1. 为什么要进程等待 子进程退出如果父进程还未结束没有管这个子进程那么就可能会造成“僵尸进程”问题进而出现内存泄漏 如果这个进程变成了“僵尸进程”那么就无法被杀死因为“无法杀死死去的进程”kill -9也不行 #includestdio.h #includeunistd.h #includestdlib.hint main() {pid_t id fork();if(id0){//创建子进程失败perror(fork fail);return 0;}else if(id 0){int cnt 5;while(cnt–){printf(I am child %d ,ppid:%d\n,getpid(),getppid());sleep(1);}exit(0);}else{while(1){printf(I am parent %d ,ppid:%d\n,getpid(),getppid());sleep(1);}}return 0; }父进程派给子进程的任务我们需要知道执行情况。例如结果是否正确是否正常退出等 父进程通过等待的方式将子进程回收获取子进程的退出信息

  1. 进程等待的方法 wait #includesys/types.h #includesys/wait.h pid_t wait(int*status); 返回值成功返回被等待进程pid失败返回-1。 参数输出型参数获取子进程退出状态,不关心则可以设置成为NULL#includestdio.h #includestdlib.h #includeunistd.h #includesys/types.h #includesys/wait.h void runChild() {int cnt 5;while(cnt–){printf(I am a child:%d, ppid:%d cnt:%d\n,getpid(),getppid(),cnt);sleep(1);} }int main() {for(int i0;i5;i){pid_t id fork();if(id 0){runChild();exit(0);}printf(I am parent:%d\n,getpid());} sleep(6);//进程回收for(int i0;i5;i){pidt ret wait(NULL);if(id0){printf(wait %d success\n,ret);}}sleep(3);return 0; }如果我们的子进程一直不退出那么父进程在默认wait的时候就不返回一直等待这种默认叫做进程阻塞状态。 另外等待的进程一定要是自己的子进程如果这个是别人的等不到结果的最后只会返回wait failed人生也如此。 waitpid pid t waitpid(pid_t pid, int *status, int options); 返回值当正常返回的时候waitpid返回收集到的子进程的进程ID如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在 参数pidPid-1,等待任一个子进程。与wait等效。Pid0.等待其进程ID与pid相等的子进程。status:WIFEXITED(status): 若为正常终止子进程返回的状态则为真。查看进程是否是正常退出WEXITSTATUS(status): 若WIFEXITED非零提取子进程退出码。查看进程的退出码options:WNOHANG: 若pid指定的子进程没有结束则waitpid()函数返回0不予以等待。若正常结束则返回该子进 程的ID。这里的第二个参数和wait一样这其实是一个输出型参数 #includestdio.h #includestdlib.h #includeunistd.h #includesys/types.h #includesys/wait.h int main() {pid_t id fork();if(id0){perror(fork error);return 1;}else if(id 0){int cnt 5;while(cnt–){printf(I am child,pid:%d,ppid:%d,cnt:%d\n,getpid(),getppid(),cnt);sleep(1);}exit(11);}else{int cnt 8;while(cnt–){printf(I am parent,pid:%d,ppid:%d,cnt:%d\n,getpid(),getppid(),cnt);sleep(1);}int status 0;pid_t ret waitpid(id,status,0);if(id ret){printf(wait success,ret:%d status:%d\n,ret,status);}sleep(3);}return 0; }运行结果
    这个个status它的类型虽然是int但它其实被当作了几部分来使用的 因为子进程退出之后父进程要收到几种信息 子进程代码是否异常退出结果是否正确如果不对是为什么不对不同的退出码表示不同的出错原因 所以status是被拆作了几部分 kill -l指令检查发现并没有0号信号这就是因为当低七位全为0的时候表示进程无异常正常退出 所以我们需要提取这个status的结果 int status 0; pidt ret waitpid(id,status,0); if(id ret) {//7f 0111111printf(wait success,ret:%d exit sig:%d,exit code:%d\n,ret,status0x7f,(status8)0xff); }当然了这里不必要我们手动自己提取系统为我们提供了宏 WIFEXITED(status)检测进程退出时是否异常WEXITSTATUS(status)提前退出码 有了这些那么就能写出完整的多进程代码了。 这里为什么要调用wait等系统调用呢为什么不直接用全局变量来接收子进程的这些信息呢 这是因为进程具有独立性所以必须通过系统调用让操作系统去拿这些数据。 非阻塞轮询 这里waitpid的第三个参数我们上面都说设置的0这表示默认进行等待如果子进程一直不退出那么父进程就一直在那等着进入阻塞状态。 如果不想一直等待那么可以采用非阻塞轮询pid t waitpid(pid_t pid, int *status, int options)第三个参数options采用宏WNOHANG。 什么叫做非阻塞轮询 就好比和别人约好了出来吃饭中午1200到xx地方碰面你自己先到了然后就一直在那等着什么也不干这就叫做默认等待也就是我们的阻塞 第二次出来玩你又先到了你吸取了上次的经验你到了之后直接打电话问对方还有多久对方答复10分钟那么对方还未到的时候你可以去别处逛逛逛的差不多了又打电话还多久对方答复5分钟好那么你提前去点餐对方到了基本上菜也就上了。这个过程就是非阻塞轮询。 #includestdio.h #includestdlib.h #includeunistd.h #includesys/types.h #includesys/wait.h int main() {pid_t id fork();if(id 0){perror(fork error);return 1;}else if(id 0){int cnt 2;while(cnt–){printf(I am child,pid:%d,ppid:%d,cnt:%d\n,getpid(),getppid(),cnt);sleep(1);}exit(27);}else{int status 0;while(1){pid_t ret waitpid(id,status,WNOHANG);if(ret0) //等待成功{if(WIFEXITED(status)){printf(进程正常退出,退出码为:%d\n,WIFEXITED(status));}else{printf(进程异常\n);}break;}else if(ret0) //等待失败{printf(wait failed\n);break;}else{printf(我在轮询\n);//sleep(1);}}}return 0; }这里可以看出当子进程未退出的时候父进程一直在轮询知道子进程退出为止 这个期间父进程就能够做自己的事情了下面来模拟这个过程 #includestdio.h #includestdlib.h #includeunistd.h #includesys/wait.h #define TASK_NUM 5 typedef void(*task_t)(); task_t tasks[TASK_NUM];//模拟任务 void task1() {printf(执行任务1,pid:%d\n,getpid()); }void task2() {printf(执行任务2,pid:%d\n,getpid()); }void task3() {printf(执行任务3,pid:%d\n,getpid()); }//任务管理 int addTask(task_t t); void initTask() {for(int i0;iTASK_NUM;i) tasks[i] NULL;addTask(task1);addTask(task2);addTask(task3); }int addTask(task_t t) {int pos 0;for(;posTASK_NUM;pos){if(!tasks[pos]) break;}if(pos TASK_NUM) return -1;tasks[pos] t;return 0; }void excuteTask() {for(int i0;iTASK_NUM;i){if(!tasks[i]) continue;tasksi;} }int main() {pid_t id fork();if(id 0){perror(fork error);return 1;}else if(id 0){int cnt 5;while(cnt–){printf(I am child,pid:%d,ppid:%d,cnt:%d\n,getpid(),getppid(),cnt);sleep(1);}exit(27);}else{initTask();int status 0;while(1){pid_t ret waitpid(id,status,WNOHANG);if(ret0) //等待成功{if(WIFEXITED(status)){printf(进程正常退出,退出码为:%d\n,WIFEXITED(status));}else{printf(进程异常\n);}break;}else if(ret0) //等待失败{printf(wait failed\n);break;}else{excuteTask();//printf(我在轮询\n);usleep(500000);}}}return 0; }在轮询过程中的任务尽量是比较轻量化的工作因为这是在等待的过程不要做太过于复杂的事情 另外子进程也不一定非得是结束之后立马回收要的是及时回收 在这些过程当中进程谁先执行是由调度器决定我们并不清楚但是父进程一定是最后退出的进程所以有了进程等待我们就能够保证父进程是最后退出的。