[英]signal handler function in multithreaded environment
在我的多線程 GUI 應用程序中,我有以下信號處理代碼。 我想改進這段代碼,使其正確且線程安全,但在信號處理中有些事情我不完全理解:
void signal_handler(int sig)
{
switch (sig)
{
case SIGTERM:
::wxLogMessage(wxT("SIGTERM signal received ..."));
break;
case SIGINT:
::wxLogMessage(wxT("SIGINT signal received ..."));
break;
case SIGUSR1:
::wxLogMessage(wxT("SIGUSR1 signal received ..."));
break;
default:
::wxLogMessage(wxT("Unknown signal received ..."));
}
// send wxCloseEvent to main application window
::wxGetApp().GetTopWindow()->Close(true);
}
我在我的 init 函數中注冊了信號處理程序:
// register signal handlers
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);
在多線程應用程序中處理信號的一種簡單方法是創建一個線程作為專用信號處理線程。 所有感興趣的信號都在每個線程中被阻塞; 沒有建立信號處理程序; 並且信號處理線程在循環中調用sigwaitinfo()
,在收到信號時對其進行處理。
這意味着您無需擔心要調用的函數是否是異步信號安全的,因為信號不是在信號處理程序中處理的——它們是由您專用的信號處理線程同步處理的,它可以調用它喜歡的任何函數(例如,它可以使用普通的 pthreads 同步函數來喚醒另一個線程)。
要非常小心:正如signal(7)頁面所說,只有很少的函數( “async-signal-safe”函數,更多信息請參見signal-safety(7) )可以(直接或間接)在信號處理程序中調用. 可能不應該在信號處理程序中調用與互斥鎖相關的函數。 另見pthreads(7)
您可能會考慮在信號處理程序中設置一個volatile sigatomic_t變量,並時常測試該標志的值。 如果您有 C++11(或 C11)原子,例如 C++11 std::atomic或 C11 <stdatomic.h>
,您可以使該volatile
變量在這個意義上也是原子的。 然后使用原子加載工具對其進行測試。
Qt 文檔建議使用以下技巧:在啟動時創建一個管道 (2)到自身,然后讓您的信號處理程序寫入 (2) ( write
系統調用被指定為異步信號安全的)單個(或多個)字節[ s] 到你的同一個進程的管道,並讓你的 GUI 事件循環輪詢(2)該管道的讀取端。
使用 Qt 處理信號的特定於 Linux 的方法可能是將signalfd(2)與QSocketNotifier一起使用(盡管名稱如此,它適用於可輪詢的文件描述符,而不僅僅是套接字)。 使用其他 GUI 工具包,您可能還可以添加要輪詢的文件描述符(來自signalfd
或pipe
的描述符)。
這個答案指的是 POSIX 線程 ( pthreads
)。
參考 1:
信號可以在線程級別處理,是的。 如果一個進程的多個線程處理一個信號,並且信號被發送到進程,但發送到特定線程,則不確定哪個線程的處理程序將處理該信號。 (詳見man pthread_kill()
)
參考2:
信號處理程序將在設置它的線程的上下文中執行。 這包括主線程。
參考 3:
如果同一類型的多個信號被發送到同一進程,它們可能會在離開信號隊列之前被壓縮成只有一個信號。 這是否可以區分到我不確定的線程級別,我不得不承認。
參考 4:
如果游戲中涉及共享資源:是的,至少對於同時訪問這些資源的處理程序代碼部分而言。 此外,這還取決於您嘗試實現的邏輯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.