[英]Is it a good practice to call pthread_sigmask in a thread created by std::thread?
1)我是 std::thread 的新手,我想知道調用pthread_sigmask()
來阻止std::thread
創建的特定線程中的某些信號是否是一個好習慣。
我不希望新線程接收諸如 SIGTERM、SIGHUP 等信號,因為主進程已經為這些信號安裝了處理程序。
那么,調用pthread_sigmask()
來阻止std::thread
創建的線程中的某些信號是一個好習慣嗎?
2)另外,我相信pthread_sigmask(SIG_BLOCK, &mask, NULL)
只適用於使用創建的線程
std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach();
並調用rotate_log()
作為啟動函數。
並且pthread_sigmask(SIG_BLOCK, &mask, NULL)
將不適用於std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach()
。
我的理解正確嗎?
void rotate_log (std::string logfile, uint32_t max_files, bool compress)
{
sigset_t mask;
sigemptyset (&mask);
sigaddset (&mask, SIGTERM);
sigaddset (&mask, SIGHUP);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
// Do other stuff.
}
void Log::log (std::string message)
{
// Lock using mutex
std::lock_guard<std::mutex> lck(mtx);
_outputFile << message << std::endl;
_outputFile.flush();
_sequence_number++;
_curr_file_size = _outputFile.tellp();
if (_curr_file_size >= max_size) {
// Code to close the file stream, rename the file, and reopen
...
// Create an independent thread to compress the file since
// it takes some time to compress huge files.
if (!_log_compression_on)
{
std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach();
}
}
}
從理論上講,即使在具有 POSIX 線程的系統上, std::thread
的實現也可能會創建非 POSIX 線程,而pthread_sigmask
不適用於此類線程。 (不過, Maxim Egorushkin 的評論是正確的——你真的應該在線程創建線程中阻塞信號,並且只解除你想要在新線程上處理的信號,以避免競爭條件。)
我不能說其他實現,但是對於 GNU/Linux 實現來說,這種事情發生的可能性極小。 當然,我也不能對這個實現發表權威性的評論,但是有太多的 C 和 C++ 代碼假設用戶空間線程(無論是 C、C++ 還是 POSIX)和內核任務(那些有 TID)。 十年前,人們仍然認為 n:m 線程庫是一種可能性(其中 POSIX 線程的早期 1:m 實現只是一個特例)。
但是今天,程序員從一個線程調用unshare (CLONE_FS)
來為該線程提供一個私有的當前目錄,與所有其他線程分開。 他們調用setfscreatecon
並期望這只會影響調用線程。 他們甚至直接調用系統調用setresuid
和setresgid
因為他們想避免 glibc 用來將更改傳播到所有線程的 setxid 廣播(內核不直接支持的東西)。 所有這些都將在 n:m 線程模型下停止工作。 所以std::thread
和 POSIX 線程必須映射到內核任務,強制執行 1:1 模型。
此外,C 和 C++ 都只有一個 GNU TLS ABI,這反過來又要求系統中只能有一種類型的線程,一個線程指針用於最終訪問線程本地數據.
這就是為什么在 GNU/Linux 上, std::thread
不太可能使用 glibc 提供的 POSIX 線程以外的任何東西的原因。
正確的方法是在創建線程之前在父級中設置所需的信號掩碼,然后在父級中將其還原。 這樣,您新創建的線程從一開始就設置了正確的信號掩碼。 (信號掩碼是從父線程繼承的)。
在線程啟動后設置信號掩碼時,有一個時間窗口,在此期間線程沒有所需的掩碼。
如果您需要在 POSIX 系統上的多線程程序中設置信號掩碼,那么pthread_sigmask
就是您需要使用的函數。 C++ 標准庫中沒有與信號掩碼交互的函數。
另外,我相信
pthread_sigmask(SIG_BLOCK, &mask, NULL)
僅適用於使用 ...
pthread_sigmask
適用於執行調用的線程,而不管線程是如何創建的。 它不適用於其他預先存在的線程。 在您的示例中,調用pthread_sigmask
的函數rotate_log
在std::thread
創建的std::thread
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.