簡體   English   中英

Boost.asio和UNIX信號處理

[英]Boost.asio & UNIX signal handling

前言

我有一個通過Boost.Asio運行的多線程應用程序。 整個應用程序只有一個boost::asio::io_service ,所有的東西都由一組線程完成。 有時需要使用fork和exec生成子進程。 當孩子終止時,我需要在上面做waitpid以檢查退出代碼和收集僵屍。 我最近添加了boost::asio::signal_set但在使用linux-2.4。*內核的舊系統中遇到了問題(不幸的是,仍然被一些客戶使用)。 在較舊的Linux內核下,線程實際上是一個特殊的進程情況,因此如果一個子程由一個線程生成,另一個線程無法使用waitpid系列調用等待它。 Asio的signal_set將信號處理程序發布到io_service ,運行此服務的任何線程都可以運行此處理程序,這不適合我的情況。 所以我決定以舊的良好信號/ sigaction方式處理信號 - 所有線程都有相同的處理程序來調用waitpid 所以還有另一個問題:

問題

當處理程序捕獲信號並且進程成功進行sigwaited時,如何從處理程序“發布”到我的io_service 在我看來,顯而易見的io_service::post()方法是不可能的,因為如果信號在錯誤的時間出現,它可能會在io_service內部互斥io_service死鎖。 我想到的唯一事情就是使用一些管道或socketpair在那里寫通知,在另一端使用async_wait ,因為它有時會處理poll()事件循環中的信號。

還有更好的解決方案嗎?

我沒有處理過boost :: asio但是我已經解決了類似的問題。 我相信我的解決方案適用於LinuxThreads和更新的NPTL線程。

我假設您要將信號“發布”到* io_service *的原因是為了中斷系統調用,因此線程/程序將干凈地退出。 它是否正確? 如果沒有,也許你可以更好地描述你的最終目標。

我嘗試了很多不同的解決方案,包括一些需要檢測正在使用哪種類型的線程的解決方案。 最終幫助我解決這個問題的是標題為信號處理程序中斷系統調用和庫函數的部分(7)。

關鍵是在信號處理線程中使用sigaction() 而不使用SA_RESTART ,為要捕獲的所有信號創建處理程序,在信號處理線程中使用pthread_sigmask(SIG_UNBLOCK,sig_set,0)取消屏蔽這些信號並屏蔽它們在所有其他線程中設置信號。 處理程序不必執行任何操作。 只是讓一個處理程序改變行為而不設置SA_RESTART允許可中斷的系統調用(如write ())來中斷。 如果你使用sigwait()系統調用,其他線程不會被中斷。

為了輕松屏蔽所有其他線程中的信號。 我啟動信號處理線程。 然后在啟動任何其他線程之前屏蔽要在主線程中處理的所有信號。 然后當其他線程啟動時,它們會復制主線程的信號掩碼。

關鍵是如果你這樣做,那么你可能不需要向* io_service *發送信號,因為你可以檢查系統調用中斷返回碼。 我不知道如何使用boost :: asio。

因此,所有這一切的最終結果是我可以捕獲我想要的信號,如SIGINT,SIGTERM,SIGHUO和SIGQUIT,以便執行干凈關閉,但我的其他線程仍然會中斷他們的系統調用,並且也可以通過任何通信干凈地退出在信號線程和系統的其余部分之間,在信號處理程序中執行任何危險操作,並且單個實現在LinuxThreads和NPTL上都有效。

也許這不是你想要的答案,但我希望它有所幫助。

注意:如果要確定系統是否正在運行LinuxThreads,可以通過生成一個線程然后將它的PID與主線程的PID進行比較來實現。 如果它們不同則是LinuxThreads。 然后,您可以為線程類型選擇最佳解決方案。

如果您已經在輪詢IO,另一個非常簡單的解決方案就是使用布爾值來表示其他線程。 布爾值總是為零或不是因此不存在部分更新和競爭條件的可能性。 然后,您可以設置此布爾標志,而不使用其他線程讀取的任何互斥鎖。 像valgrind這樣的工具不會喜歡它,但在實踐中它可以工作。

如果你想更加正確,你可以使用gcc的原子,但這是編譯器特定的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM