[英]waitpid with execl used in child returns -1 with ECHILD?
如果我正在使用execl,何時需要使用waitpid是子進程,可能需要一些時間才能完成?
當我在父級中使用waitpid時,它使我的孩子正在運行,因為waitpid的返回值是0。一段時間后,我試圖在另一個函數中使用waitpid,在該函數中我將ECHILD返回-1。 如果不確定天氣孩子是否完成,應該何時使用waitpid?
//pid_t Checksum_pid = fork();
Checksum_pid = fork();
if (Checksum_pid == 0)
{
execl(path, name, argument as needed, ,NULL);
exit(EXIT_SUCCESS);
}
else if (Checksum_pid > 0)
{
pid_t returnValue = waitpid(Checksum_pid, &childStatus, WNOHANG);
if ( returnValue > 0)
{
if (WIFEXITED(childStatus))
{
printf("Exit Code: _ WEXITSTATUS(childStatus)") ;
}
}
else if ( returnValue == 0)
{
//Send positive response with routine status running (0x03)
printf("Child process still running") ;
}
else
{
if ( errno == ECHILD )
{
printf(" Error ECHILD!!") ;
}
else if ( errno == EINTR )
{
// other real errors handled here.
printf(" Error EINTR!!") ;
}
else
{
printf("Error EINVAL!!") ;
}
}
}
else
{
/* Fork failed. */
printf("Fork Failed") ;
}
如果信號SIGCHLD被忽略(這是默認設置),並且您跳過了Jonathan提到的WNOHANG,waitpid將掛起,直到子項退出,然后代碼ECHILD失敗。 我本人是在父進程僅應等待子進程完成的情況下遇到此問題的,而為SIGCHLD注冊處理程序似乎有點過頭了。 自然的后續問題是“在這種情況下是否可以將ECHILD視為預期事件,還是我總是應該為SIGCHLD編寫處理程序?”,但對此我沒有答案。
從waitpid(2)的文檔中 :
成就
(用於waitpid()或waitid())由pid(waitpid())或idtype和id(waitid())指定的進程不存在或不是調用進程的子進程。 (如果將SIGCHLD的操作設置為SIG_IGN,這可能會發生在自己的孩子身上。另請參見關於線程的Linux Notes部分。)
再往下走
POSIX.1-2001指定如果將SIGCHLD的處置設置為SIG_IGN或為SIGCHLD設置SA_NOCLDWAIT標志(請參見sigaction(2)),則終止的子代不會成為僵屍,並且對wait()或waitpid( )將阻塞,直到所有子級都終止,然后在errno設置為ECHILD時失敗。 (原始POSIX標准未指定將SIGCHLD設置為SIG_IGN的行為。請注意,即使SIGCHLD的默認設置為“ ignore”,將設置顯式設置為SIG_IGN也會導致對僵屍進程子進程的不同處理。)Linux 2.6符合此要求。規格。 但是,Linux 2.4(及更早版本)沒有:如果在忽略SIGCHLD的同時進行了wait()或waitpid()調用,則該調用的行為就像未忽略SIGCHLD一樣,也就是說,該調用將阻塞直到下一個子進程終止,然后返回該子進程的進程ID和狀態。
另請參閱此答案 。
如果您等待WNOHANG
,那么除非您的孩子已經死亡,否則您將不會獲得任何有用的狀態-甚至可能還沒有去世(當父級執行該操作時,它可能仍在等待從磁盤加載可執行文件)。 waitpid()
)。
如果您想知道孩子已經完成,請不要使用WNOHANG
-在第三個參數中使用0
,除非您想了解未跟蹤或繼續的進程。 這將一直等待,直到由Checksum_pid
標識的進程退出,或者系統以某種神秘的方式失去了對它的跟蹤(我從未見過這種情況)。
此代碼產生Exit Code: 0
作為輸出:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t Checksum_pid = fork();
if (Checksum_pid < 0)
printf("Fork Failed\n");
else if (Checksum_pid == 0)
{
execl("/bin/sleep", "/bin/sleep", "2", NULL);
exit(EXIT_FAILURE);
}
else
{
int childStatus;
pid_t returnValue = waitpid(Checksum_pid, &childStatus, 0);
if (returnValue > 0)
{
if (WIFEXITED(childStatus))
printf("Exit Code: %d\n", WEXITSTATUS(childStatus));
else
printf("Exit Status: 0x%.4X\n", childStatus);
}
else if (returnValue == 0)
printf("Child process still running\n");
else
{
if (errno == ECHILD)
printf(" Error ECHILD!!\n");
else if (errno == EINTR)
printf(" Error EINTR!!\n");
else
printf("Error EINVAL!!\n");
}
}
return 0;
}
它與您的代碼非常相似; 我只是將對fork()
的檢查移到了頂部。 我仍然希望擺脫if
語句的“繁忙樹”,但這並不重要。 運行此代碼會怎樣? 為了得到ECHILD
錯誤,您必須更改什么(可以更改它以便得到ECHILD
錯誤)嗎?
當您設法從中獲得代碼來重現該問題時,我們可以弄清楚為什么您會得到這種行為。
在帶有GCC 4.8.2的Mac OS X 10.9.2 Mavericks和帶有GCC 4.8.1的Ubuntu 13.10上進行了測試(我需要添加-D_XOPEN_SOURCE=700
以使其能夠使用嚴格的編譯標志進行編譯; Mac OS X無需使用它即可進行編譯),但我不希望在其他地方得到不同的結果。
int start(int Area)
{
int childStatus;
pid_t Checksum_pid = fork();
if(Checksum_pid < 0)
{
/* Fork failed. */
printf(" Fork Failed") ;
}
else if (Checksum_pid == 0)
{
for (int i = 0; i<5; i++)
{
if ( g_area[i] == Area)
{
execl(ScriptPath, ScriptName, NULL);
}
}
exit(EXIT_FAILURE);
}
else
{
/* This is the parent process. */
pid_t returnValue = waitpid(Checksum_pid, &childStatus, 0);
if ( returnValue > 0)
{
// Check if child ended normally
printf("WAITPID Successful") ;
if (WIFEXITED(childStatus))
{
printf("Exit Code: _ WEXITSTATUS(childStatus)");
}
}
else if ( returnValue == 0)
{
printf("Child process still running") ;
}
else
{
if ( errno == ECHILD )
{
printf("Error ECHILD!!") ;
}
else if ( errno == EINTR )
{
printf("Error EINTR!!") ;
}
else
{
printf(" Error EINVAL!!") ;
}
retCode = FAILED;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.