我想在Linux上創建一個包裝器,它控制一次允許多少個併發執行的東西。爲此,我正在使用系統範圍計數信號量。我創建信號量,執行sem_wait()
,啓動子進程,然後在子進程結束時執行sem_post()
。沒事兒。信號安全使用sem_wait()/ sem_post()
問題是如何安全地處理髮送到這個包裝的信號。如果它沒有捕獲到信號,那麼命令可能會終止而不執行sem_post()
,導致信號計數永久減少1。所以,我創建了一個信號處理程序,它的作用是sem_post()
。但仍然存在問題。
如果處理程序是sem_wait()
連接之前進行,信號可以在sem_wait()
完成之前到達,造成sem_post()
沒有sem_wait()
發生。如果我在設置信號處理程序之前執行sem_wait()
,則可能會發生相反的情況。
明顯的下一步是在設置處理程序和sem_wait()
期間阻止信號。這是我現在有僞代碼:
void handler(int sig)
{
sem_post(sem);
exit(1);
}
...
sigprocmask(...); /* Block signals */
sigaction(...); /* Set signal handler */
sem_wait(sem);
sigprocmask(...); /* Unblock signals */
RunChild();
sem_post(sem);
exit(0);
現在的問題是,sem_wait()
可以阻止在此期間,信號被阻斷。試圖殺死進程的用戶最終可能會訴諸於「kill -9」,這是我不想鼓勵的行爲,因爲無論如何我都無法處理這種情況。我可以使用sem_trywait()
一小段時間,並測試sigpending()
但影響公平性,因爲不再保證等待信號量最長的進程將接下來運行。
這裏有一個真正安全的解決方案,它允許我在信號量採集期間處理信號嗎?我正在考慮訴諸全球性的「我有信號量」,並取消信號阻塞,但自從獲得信號量和設置全局以來,這並非100%安全,這不是原子性的,但可能比等待時阻止信號更好。
對不起,如果我不清楚。sem_wait()不會像您所說的那樣導致信號被阻塞,但我正在使用sigprocmask()來阻止它們。但是,我認爲你有正確的解決方案,即查看EINTR錯誤代碼,這意味着處理程序不應該退出,但設置一些標誌來表示「退出時間」。我會測試一下。謝謝。 – Jeremy 2009-06-01 23:46:29
工作。我刪除了信號的阻塞,並將信號處理程序更改爲設置全局含義,現在是時候退出了。如果sem_wait()返回一個錯誤,那麼我退出這是很好,並保留信號計數。如果我在等孩子,我也測試timeToQuit global。如果是時候退出,我殺了孩子,並做一個sem_post(),它保留了信號計數。謝謝。這應該是信號安全的,忽略kill -9。 – Jeremy 2009-06-02 00:04:45