網站首頁 編程語言 正文
進程等待的必要
當一個進程終止的時候,它的資源,比如說PCB,數據等不會被立馬清理掉。它會保持在已經終止的狀態,這種狀態稱為“僵尸狀態”,直到被父進程確認。父進程wait,即父進程向內核確認子進程已經終止,可以為子進程“收尸”了,內核會把子進程的退出信息傳給父進程,然后清理掉子進程的資源,這個時候子進程才算真正地終止了!
總結:
- 父進程等待,可以獲取子進程的退出信息,知道子進程的執行結果。
- 父進程等待,可以釋放子進程的資源,讓子進程真正地退出,避免一直消耗系統的存儲資源,造成“內存泄露”等危害。
- 父進程等待,可以保證時序的問題,子進程先于父進程退出,避免讓子進程變為孤兒進程。
進程等待的方法
wait函數
一個進程可以通過調用wait函數等待子進程。wait函數是系統調用函數。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
返回值:返回被等待進程的pid,如果等待失敗,返回-1。
參數:輸出型參數,可以獲取子進程的退出狀態,如果不需要獲取子進程的退出狀態,則設置為NULL。
測試:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
pid_t id = fork(); //創建子進程
if(id == 0)
{
//child
//執行5秒
int cnt = 5;
while(cnt)
{
printf("child[%d] , cnt:%d\n", getpid(), cnt);
sleep(1);
cnt--;
}
exit(EXIT_SUCCESS);
}
sleep(10);
pid_t ret = wait(NULL);
if(ret > 0)
{
//wait success, ret is pid;
printf("father wait child[%d] success\n", ret);
}
else{
//wait failed.
printf("father wait failed\n");
}
return 0;
}
現象:子進程執行5秒后,終止了,但是內核沒有立馬清理掉它的資源,所以此時是僵尸狀態,再過了5秒之后,父進程休眠完畢,然后等待子進程,確認子進程已經終止,返回子進程的pid,然后內核開始清理子進程資源,子進程真正地終止了,又過了5秒后父進程也終止了。
通過wait函數的輸出型參數可以獲得子進程的退出信息。
waitpid函數
waitpid函數也可以使得父進程等待子進程
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
先不關心第二個和第三個參數,第二個參數可以設置為NULL,第三個參數暫時設置為0。
第一個參數:
1、如果第一個參數pid傳的是某個具體的進程的進程ID,表示等待該指定進程
2、如果第一個參數pid傳的是-1,表示等待父進程的任意子進程。
第三個參數:
- 傳的是0,表示父進程是掛起等待子進程的(阻塞等待)。可以理解為“父進程在等待子進程的過程中,什么事情也沒做,在干等”。
- 傳的是宏WNOHANG,表示父進程是非阻塞等待。若等待的子進程還沒有終止,那么waitpid函數立即返回0,不予以等待。若等待的子進程已經正常結束,那么waitpid函數返回等待子進程的PID
wait(&status) 等價于 waitpid(-1, &status, 0)
【注意事項】
- 如果子進程已經退出,調用wait/waitpid時,wait/waitpid會立即返回,獲得子進程退出信息,并且釋放被等待子進程資源。
- 如果在任意時刻調用wait/waitpid,子進程存在且還在正常運行,則父進程可能會發生阻塞。
- 如果試圖等待一個當前不存在的進程,wait/waitpid會調用出錯,并立即返回。
獲取子進程退出信息
在上述并沒有具體解釋參數status的作用。
- 在wait和waitpid函數中,status的作用是一樣的,它是輸出型參數。
- 如果給status傳的是NULL,則表示不需要獲取子進程的退出信息。
- 如果給status傳的是非NULL,則可以獲取被等待進程的退出信息。
status是一個指向整形的指針。但是一個進程的退出信息那么多,怎么可能會那么簡單地用一個整型就知道進程的退出信息了呢?實際上,并不是簡單地看待status指向的整形,而是當作位圖來看,一個整型有32位,這樣就可以全面地描述被等待進程的退出信息了。
只用研究低16個比特位。
進程退出的情況有四種:
1、正常退出(自愿,代碼執行完,結果正確)
2、錯誤退出(自愿,代碼執行完,結果不正確)
3、異常退出(非自愿,代碼未執行完,退出碼無意義)
4、被其他進程終止(非自愿,代碼未執行完,退出碼無意義)
這四種情況,可以按照進程是否收到信號來分類,第一種和第二種進程未收到信號,第三和第四種進程收到信號。
當被等待進程不是被信號所終止時,低8位全是0,而次低8位則是被等待進程的退出碼。
當被等待進程是被信號所終止時,低7位表示被等待進程收到的信號。
如果進程是正常終止,如何顯示地知道退出碼?
如果進程是收到信號而終止,如何知道它收到了什么信號?直接就是低7位表示的是進程收到的信號,如果是非法的信號,說明它沒有收到信號,這個值是無效的。
測試:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
pid_t id = fork(); //創建子進程
if(id == 0)
{
//child
//執行5秒
int cnt =7;
while(cnt)
{
printf("child[%d] , cnt:%d\n", getpid(), cnt);
sleep(1);
cnt--;
}
exit(12);
}
sleep(10);
int status;
pid_t ret = waitpid(id, &status, 0);
if(ret > 0)
{
//wait success, ret is pid;
printf("father wait child[%d] success\n", ret);
}
else{
//wait failed.
printf("father wait failed\n");
}
printf("get a exit num : %d\n, get a single:%d", (status >> 8) & 0XF FFF, status & 0XFFFF);
sleep(2);
return 0;
}
當然,還可以不需要進行位運算,系統提供了兩個宏,可以得到退出信息
- WIFEXITED(status):如果被等待進程正常退出則未真。
- WEXITSTATUS(status):如果WFIEXITED(status)為真,提取被等待進程的退出碼。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
pid_t id = fork(); //創建子進程
if(id == 0)
{
//child
//執行5秒
printf("i am child precess\n");
sleep(5);
exit(12);
}
sleep(3);
int status;
printf("father begin wait\n");
pid_t ret = waitpid(id, &status, 0);
if(ret > 0)
{
//wait success, ret is pid;
printf("father wait child[%d] success\n", ret);
}
else{
//wait failed.
printf("father wait failed\n");
}
if(WIFEXITED(status))
{
printf("exit code : %d\n", WEXITSTATUS(status));
}
else{
printf("get a signal\n");
}
sleep(2);
return 0;
}
執行結果
原文鏈接:https://blog.csdn.net/qq_56870066/article/details/125188459
相關推薦
- 2022-05-13 C++ std::thread 線程的傳參方式
- 2022-12-30 React?Refs轉發實現流程詳解_React
- 2022-08-17 Qt?QFrame的具體使用_C 語言
- 2022-11-12 Python?sklearn分類決策樹方法詳解_python
- 2022-04-10 Git常用命令介紹_其它綜合
- 2023-12-09 添加依賴時,出現了此問題maven Cannot resolve org.apache.dubbo:
- 2022-09-21 Python機器學習庫scikit-learn入門開發示例_python
- 2022-09-08 pandas庫中to_datetime()方法的使用解析_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支