大家好,欢迎来到IT知识分享网。
3.4.8.waitpid介绍
3.4.8.1、waitpid和wait差别
相同点 是功能, 不同点是 使用 方法
(1)基本功能一样,都是用来回收子进程
(2)waitpid可以回收指定 PID 的子进程
(3)waitpid可以阻塞式或非阻塞式两种工作模式
3.4.8.2、waitpid原型介绍
(1)参数
(2)返回值
3.4.8.3、代码实例
(1)使用waitpid实现wait的效果
ret = waitpid(-1, &status, 0); -1表示不等待某个特定PID的子进程而是回收任意一个子进程,0表示用默认的方式(阻塞式)来进行等待,返回值ret是本次回收的子进程的PID
(2)ret = waitpid(pid, &status, 0); 等待回收PID为pid的这个子进程,如果当前进程并没有一个ID号为pid的子进程,则返回值为-1;如果成功回收了pid这个子进程则返回值为回收的进程的PID
(3)ret = waitpid(pid, &status, WNOHANG);这种表示父进程要非阻塞式的回收子进程。此时如果父进程执行waitpid时子进程已经先结束等待回收则waitpid直接回收成功,返回值是回收的子进程的PID;如果父进程waitpid时子进程尚未结束则父进程立刻返回(非阻塞),但是返回值为0(表示回收不成功)。
代码:
ret = waitpid(-1,&status,0); /* waitpid ,-1表示不管是那个子进程都回收 ,0 表示 阻塞式 */
只是 更改了 这一句,其他的 和 wait 都一样,效果也一样
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(void) { /* 接收 fork 的返回值 */ pid_t p1 = -1; /* 接收 wait waitpid 的返回值 */ pid_t ret = -1; /* wait waitpid 传参,进程状态信息 */ int status = -1; p1 = fork(); //fork 函数返回 2 次 : 等于0 是子进程, 大于0是父进程 if(0 == p1) { /* 这里一定是 子进程 , 子进程先结束,成为僵尸进程 ,一定要保证子进程先结束 */ printf("子进程 child pid = %d \n", getpid()); return 99; } else if (p1 > 0) { /* 这里一定是 父进程 */ ret = waitpid(-1,&status,0); /* waitpid ,-1表示不管是那个子进程都回收 ,0 表示 阻塞式 */ printf("子进程已经被回收,子进程pid = %d \n", ret); printf("子进程是否正常退出:%d \n", WIFEXITED(status)); /* WIFEXITED 判断是否正常退出 */ printf("子进程是否 非正常退出:%d \n", WIFSIGNALED(status)); /* WIFSIGNALED 判断是否 非正常退出 */ printf("子进程正常终止情况下的 进程返回值:%d \n", WEXITSTATUS(status)); /* WEXITSTATUS 正常终止情况下的 进程返回值 */ } else { /* 这里一定是 fork出错了 */ perror("fork"); return -1; } return 0; }
运行结果:
实例 2 , waitpid 用指定 pid 回收 子进程
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(void) { /* 接收 fork 的返回值 */ pid_t p1 = -1; /* 接收 wait waitpid 的返回值 */ pid_t ret = -1; /* wait waitpid 传参,进程状态信息 */ int status = -1; p1 = fork(); //fork 函数返回 2 次 : 等于0 是子进程, 大于0是父进程 if(0 == p1) { /* 这里一定是 子进程 , 子进程先结束,成为僵尸进程 ,一定要保证子进程先结束 */ printf("子进程 child pid = %d \n", getpid()); return 99; } else if (p1 > 0) { printf(" 父进程中打印 子进程id = %d \n ",p1); /* 这里一定是 父进程 */ /* 这里一定是 父进程 */ ret = waitpid(p1,&status,0); /* waitpid ,-1表示不管是那个子进程都回收 ,0 表示 阻塞式 */ printf("子进程已经被回收,子进程pid = %d \n", ret); printf("子进程是否正常退出:%d \n", WIFEXITED(status)); /* WIFEXITED 判断是否正常退出 */ printf("子进程是否 非正常退出:%d \n", WIFSIGNALED(status)); /* WIFSIGNALED 判断是否 非正常退出 */ printf("子进程正常终止情况下的 进程返回值:%d \n", WEXITSTATUS(status)); /* WEXITSTATUS 正常终止情况下的 进程返回值 */ } else { /* 这里一定是 fork出错了 */ perror("fork"); return -1; } return 0; }
运行结果:
实例 3 ,如果传一个 错误的 pid , waitpid会返回 什么呢?????
传一个 错误的 pid : p1+6
ret = waitpid(p1+6,&status,0); /* waitpid ,-1表示不管是那个子进程都回收 ,0 表示 阻塞式 */
运行结果:
实例 4 waitpid 非阻塞式 回收 WNOHANG
ret = waitpid(p1,&status,WNOHANG); /* waitpid ,-1表示不管是那个子进程都回收 ,WNOHANG 表示 非阻塞式 */
代码:
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(void) { /* 接收 fork 的返回值 */ pid_t p1 = -1; /* 接收 wait waitpid 的返回值 */ pid_t ret = -1; /* wait waitpid 传参,进程状态信息 */ int status = -1; p1 = fork(); //fork 函数返回 2 次 : 等于0 是子进程, 大于0是父进程 if(0 == p1) { /* 这里一定是 子进程 , 为了 保证 父进程 先执行 waitpid 非阻塞式 回收 ,子进程sleep , 先让父进程执行 */ sleep(1); /* 这里一定是 子进程 , 子进程先结束,成为僵尸进程 ,一定要保证子进程先结束 */ printf("子进程 child pid = %d \n", getpid()); return 99; } else if (p1 > 0) { printf(" 父进程中打印 子进程id = %d \n ",p1); /* 这里一定是 父进程 */ /* 这里一定是 父进程 */ ret = waitpid(p1,&status,WNOHANG); /* waitpid ,-1表示不管是那个子进程都回收 ,WNOHANG 表示 非阻塞式 */ printf("子进程已经被回收,子进程pid = %d \n", ret); printf("子进程是否正常退出:%d \n", WIFEXITED(status)); /* WIFEXITED 判断是否正常退出 */ printf("子进程是否 非正常退出:%d \n", WIFSIGNALED(status)); /* WIFSIGNALED 判断是否 非正常退出 */ printf("子进程正常终止情况下的 进程返回值:%d \n", WEXITSTATUS(status)); /* WEXITSTATUS 正常终止情况下的 进程返回值 */ } else { /* 这里一定是 fork出错了 */ perror("fork"); return -1; } return 0; }
运行结果:
实例 4 waitpid 非阻塞式 回收 WNOHANG
把 sleep 加入到 父进程 ,让子进程先结束,子进程进入僵尸进程后 ,父进程 去回收
代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
/* 接收 fork 的返回值 */
pid_t p1 = -1;
/* 接收 wait waitpid 的返回值 */
pid_t ret = -1;
/* wait waitpid 传参,进程状态信息 */
int status = -1;
p1 = fork(); //fork 函数返回 2 次 : 等于0 是子进程, 大于0是父进程
if(0 == p1)
{
/* 这里一定是 子进程 , 子进程先结束,成为僵尸进程 ,一定要保证子进程先结束 */
printf(“子进程 child pid = %d \n”, getpid());
return 99;
}
else if (p1 > 0)
{
/* 父进程 加入 sleep */
sleep(1);
printf(” 父进程中打印 子进程id = %d \n “,p1); /* 这里一定是 父进程 */
/* 这里一定是 父进程 */
ret = waitpid(p1,&status,WNOHANG); /* waitpid ,-1表示不管是那个子进程都回收 ,WNOHANG 表示 非阻塞式 */
printf(“子进程已经被回收,子进程pid = %d \n”, ret);
printf(“子进程是否正常退出:%d \n”, WIFEXITED(status)); /* WIFEXITED 判断是否正常退出 */
printf(“子进程是否 非正常退出:%d \n”, WIFSIGNALED(status)); /* WIFSIGNALED 判断是否 非正常退出 */
printf(“子进程正常终止情况下的 进程返回值:%d \n”, WEXITSTATUS(status)); /* WEXITSTATUS 正常终止情况下的 进程返回值 */
}
else
{
/* 这里一定是 fork出错了 */
perror(“fork”);
return -1;
}
return 0;
}
运行结果:
3.4.8.4、竟态初步引入
(1)竟态全称是:竞争状态,多进程环境下,多个进程同时抢占系统资源(内存、CPU、文件IO)
进程1 读1.txt, 进程2 也同时读1.txt
如果 没有 sleep 我们就不确定 到底是 父进程先 结束,还是 子进程先结束!!!
(3)写程序当然不希望程序运行的结果不确定,所以我们写程序时要尽量消灭竞争状态。操作系统给我们提供了一系列的消灭竟态的机制,我们需要做的是在合适的地方使用合适的方法来消灭竟态。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/119699.html