簡體   English   中英

在 std::thread 創建的線程中調用 pthread_sigmask 是一個好習慣嗎?

[英]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並期望這只會影響調用線程。 他們甚至直接調用系統調用setresuidsetresgid因為他們想避免 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_logstd::thread創建的std::thread

暫無
暫無

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

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