2012-09-17 34 views
0

我已經有了一個應對方案,其中主要過程分叉成4點的孩子,互相配合:睡眠過程中不給信號

process0被打開FIFO文件(O_WRONLY),從每次讀1個字節STDIN使用讀取功能,使用寫入和關閉FIFO文件寫入FIFO

process1正在等待共享內存爲空(我正在使用共享內存表的第一個字節if(tab [0] == 0)檢查它是否爲空)打開FIFO文件(O_RDONLY),從中讀取,將這一個字節轉換爲十六進制並將其保存到共享內存中。然後它關閉FIFO和設置標籤[0],這是共享存儲器表1。

過程2是從共享存儲器讀出,如果標籤[0] == 1看完之後將數據寫入管道

process3被從管道讀取並寫入STDIN

這一切都很完美。當我想添加信號時,問題就開始了。我使用信號量來同步p0和p1,同步p1和p2的信號以及消息隊列來同步p2和p3。除了例如process1處於休眠模式的時間以外,它也可以正常工作。當它想要從FIFO中讀取並且必須等待數據被傳輸時,它進入這種模式。我想。我一直在閱讀。

processes hierarchy

這裏是我發現,我認爲可能的原因:

「當過程進行系統調用,而在用戶模式(1),它進入狀態2的地方開始以內核模式運行,此時假定系統調用是讀取硬盤上的一個文件,因爲讀取不是立即執行,進程進入休眠狀態,等待系統讀取的事件磁盤和數據已準備就緒,現在處於狀態4.數據準備就緒後,進程被喚醒,這並不意味着它立即運行,而是再次準備在主內存中運行(3)。 「

我想我明白了,但我該如何避免這種情況?我希望我的程序始終對信號做出反應。當我通過「kill」發送信號時,是否有某種方法可以將進程狀態從睡眠狀態更改爲運行狀態?我能否以某種方式告訴進程停止「等待系統讀取了磁盤並且數據已準備好」的事件?

,這裏是我的代碼,如果有人想看看吧:

Program's code

回答

1

如果我正確理解你的問題,處理1可以取出線442(源)掛了電話,不迴應的信號,因爲它是在read

顯而易見的答案就是不要阻止read()。檢查描述符以查看是否有任何要閱讀的內容,如果沒有,則繼續前進。請閱讀fcntl/ioctl以及如何進行非阻塞式讀取。

1

如果發生信號,您的觀察可能是(大多數)系統調用默認重新啓動。簡而言之,這意味着代碼卡在系統調用中會在信號傳遞時喚醒用戶空間,但在信號處理程序運行後恢復系統調用。

如果使用sigaction()建立信號處理程序而不是signal()函數。,當信號被捕獲時系統調用不會重新啓動,而是失敗並將errno設置爲EINTR。 這意味着你必須處理這樣一個事實,即由於信號被傳遞,系統調用可能在任何地方「失敗」。 (signal()默認會在linux重啓時引起系統調用,在包含signal.h頭文件之前可以通過某些特性宏來控制它)。sigaction()是否導致系統調用重啓由flag SA_RESTART控制當建立信號處理器時)