2012-10-15 20 views
2

非常奇怪的錯誤,也許有人會看到我失蹤的東西。避免在C++中生成殭屍進程

我有一個C++程序,它分離出一個bash shell,然後將命令傳遞給它。

定期地,這些命令將包含無意義,並且bash進程將掛起。我發現這個使用semtimedwait,然後運行一個小功能是這樣的:

if (kill(*bash_pid, SIGKILL)) { 
    cerr << "Error sending SIGKILL to the bash process!" << endl; 
    exit(1); 
} else { 
    // collect exit status 
    long counter = 0; 
    do { 
     pid = waitpid(*bash_pid, &status, WNOHANG); 
     if (pid == 0) { // status not available yet 
      sleep(1); 
     } 
     if(counter++ > 5){ 
      cerr << "ERROR: Bash child process ignored SIGKILL >5 sec!" << endl; 
     } 
    } while (pid != *bash_pid && pid != -1); 
    if(pid == -1){ 
     cerr << "Failed to clean up zombie bash process!" << endl; 
     exit(1); 
    } 

    // re-initialized bash process 
    *bash_pid = init_bash(); 
} 

假設我理解waitpid函數的正確運作,這應該先發SIGKILL的外殼,然後基本上是坐在一個自旋鎖,試圖收穫最終的過程。最終,它會成功,然後用init_bash()開始一個新的bash進程。

至少,這是應該發生的。相反,子進程的退出狀態永遠不會被收集,並且它會繼續作爲殭屍進程存在。儘管如此,父母確實退出循環並管理重新啓動bash進程,並繼續正常執行。最終會生成太多殭屍,並且系統將耗盡pid。

此外:

  • 叉被稱爲在程序中的一個地方,裏面init_bash。
  • 檢查防止init_bash被調用,除了在程序開始和調用上述函數之後。

想法?

+0

一個正在運行的解決方法是調用signal(SIGCHLD,SIG_IGN);在主要的頂部,但這並不理想。我想直接收穫子進程。 –

回答

1

我讀過的文章表明,殭屍進程的原因是一個子進程執行退出,但父母從不收集孩子的退出。

本文提供了several ways to kill a zombie process from the command line。一種技術是使用除SIGKILL以外的其他信號作爲SIGTERM實例。

article has an answer which suggests SIGKILL不應該使用。

其中一種技術是殺死父母,從而也殺死其子進程,包括任何殭屍。作者指出,在操作系統重新啓動之前,似乎有一些子進程保持殭屍狀態。

您沒有提及用於將命令傳遞給子進程的機制。然而,一種選擇可能是通過將子進程與其父進程斷開,從而鬆開子進程,類似於終端進程的子進程可以從終端會話中斷開的方式。這樣孩子將成爲自己的過程,如果有問題可能會退出而不會成爲殭屍。

+0

嗨,理查德,謝謝你的想法。澄清,兒童進程最初並沒有死亡。我提供的代碼首先殺死進程,然後嘗試使用waitpid收集其退出狀態。不知何故,退出狀態似乎有可能在沒有子進程退出的情況下被收集。 –

+0

@JohnDoucette,嗯。所以我想知道在發送信號之後和在等待pid之前做了100毫秒的睡眠的結果。 –