[英]Avoiding a fork()/SIGCHLD race condition
請考慮以下fork()
/ SIGCHLD
偽代碼。
// main program excerpt
for (;;) {
if ( is_time_to_make_babies ) {
pid = fork();
if (pid == -1) {
/* fail */
} else if (pid == 0) {
/* child stuff */
print "child started"
exit
} else {
/* parent stuff */
print "parent forked new child ", pid
children.add(pid);
}
}
}
// SIGCHLD handler
sigchld_handler(signo) {
while ( (pid = wait(status, WNOHANG)) > 0 ) {
print "parent caught SIGCHLD from ", pid
children.remove(pid);
}
}
在上面的例子中,有一個競爭條件。 “ /* child stuff */
”可能在“ /* parent stuff */
”開始之前完成,這可能導致孩子的pid在退出后被添加到子列表中,並且永遠不會被刪除。 當應用程序關閉的時候,父母將無休止地等待已經完成的孩子完成。
我能想到的一個解決方案就是有兩個列表: started_children
和finished_children
。 我會在我現在添加到children
的同一個地方添加到started_children
。 但是在信號處理程序中,我將添加到finished_children
而不是從children
節點中刪除。 當應用關閉時,父母可以等待,直到started_children
和finished_children
之間的差異為零。
我能想到的另一種可能的解決方案是使用共享內存,例如,共享父項的子項列表,並讓子項.add
和.remove
自己? 但我對此並不太了解。
編輯:另一個可能的解決方案,這是我想到的第一件事,就是簡單地在/* child stuff */
開始添加一個sleep(1)
/* child stuff */
但這對我來說很有趣,這就是我把它留下來的原因。 我甚至不確定它是100%修復。
那么,你如何糾正這種競爭條件? 如果有一個完善的推薦模式,請告訴我!
謝謝。
最簡單的解決方案是使用sigprocmask()
在fork()
之前阻塞SIGCHLD信號,並在處理完pid后在父代碼中解除阻塞。
如果孩子死亡,在解鎖信號后將調用SIGCHLD的信號處理程序。 這是一個關鍵的部分概念 - 在你的情況下,臨界部分在fork()
之前開始並在children.add()
之后結束。
如果你不能使用關鍵片段,也許一個簡單的計數器就可以完成這項工作。 添加時為+1,刪除時為-1,沒有首先發生的任何一個,當完成后最終可以獲得零。
除了現有的“孩子”外,還增加了一個新的數據結構“早期死亡”。 這將保持兒童的內容清潔。
// main program excerpt
for (;;) {
if ( is_time_to_make_babies ) {
pid = fork();
if (pid == -1) {
/* fail */
} else if (pid == 0) {
/* child stuff */
print "child started"
exit
} else {
/* parent stuff */
print "parent forked new child ", pid
if (!earlyDeaths.contains(pid)) {
children.add(pid);
} else {
earlyDeaths.remove(pid);
}
}
}
}
// SIGCHLD handler
sigchld_handler(signo) {
while ( (pid = wait(status, WNOHANG)) > 0 ) {
print "parent caught SIGCHLD from ", pid
if (children.contains(pid)) {
children.remove(pid);
} else {
earlyDeaths.add(pid);
}
}
}
編輯:如果你的進程是單線程的,這可以簡化 - earlyDeaths不必是一個容器,它只需要保持一個pid。
也許是一個樂觀的算法? 嘗試children.remove(pid),如果失敗,繼續生活。
或者在嘗試刪除之前檢查pid是否在兒童中?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.