繁体   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