简体   繁体   English

在 std::thread 创建的线程中调用 pthread_sigmask 是一个好习惯吗?

[英]Is it a good practice to call pthread_sigmask in a thread created by std::thread?

1) I'm new to std::thread and I would like to know whether it is a good practice to call pthread_sigmask() to block some signals in a particular thread created by std::thread . 1)我是 std::thread 的新手,我想知道调用pthread_sigmask()来阻止std::thread创建的特定线程中的某些信号是否是一个好习惯。

I don't want the new thread to receive signals such as SIGTERM, SIGHUP, etc., because the main process has already installed handlers for these signals.我不希望新线程接收诸如 SIGTERM、SIGHUP 等信号,因为主进程已经为这些信号安装了处理程序。

So, is it a good practice to call pthread_sigmask() to block some signals in a thread created by std::thread ?那么,调用pthread_sigmask()来阻止std::thread创建的线程中的某些信号是一个好习惯吗?

2) Also, I believe the effect of pthread_sigmask(SIG_BLOCK, &mask, NULL) will only apply to the thread created using 2)另外,我相信pthread_sigmask(SIG_BLOCK, &mask, NULL)只适用于使用创建的线程

std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach();

and calling rotate_log() as the start function.并调用rotate_log()作为启动函数。

And the effect of pthread_sigmask(SIG_BLOCK, &mask, NULL) will not apply to the thread where std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach() is called.并且pthread_sigmask(SIG_BLOCK, &mask, NULL)将不适用于std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach()

Is my understanding correct?我的理解正确吗?

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();
            }
        }
    }

In theory, it is possible that an implementation of std::thread will create a non-POSIX thread even on a system which has POSIX threads, and pthread_sigmask would not work for such threads.从理论上讲,即使在具有 POSIX 线程的系统上, std::thread的实现也可能会创建非 POSIX 线程,而pthread_sigmask不适用于此类线程。 ( Maxim Egorushkin's comment is correct, though—you really should block signals in the thread-creating thread and only unblock those you want handled on the new thread, to avoid race conditions.) (不过, Maxim Egorushkin 的评论是正确的——你真的应该在线程创建线程中阻塞信号,并且只解除你想要在新线程上处理的信号,以避免竞争条件。)

I cannot speak for other implementations, but it it is extremely unlikely that such a thing will happen for the GNU/Linux implementation.我不能说其他实现,但是对于 GNU/Linux 实现来说,这种事情发生的可能性极小 I cannot speak authoritatively for this implementation either, of course, but there is simply too much C and C++ code out there that assumes a 1:1 mapping between userspace threads (whether C, C++, or POSIX) and kernel tasks (those things that have TIDs).当然,我也不能对这个实现发表权威性的评论,但是有太多的 C 和 C++ 代码假设用户空间线程(无论是 C、C++ 还是 POSIX)和内核任务(那些有 TID)。 Ten years ago, people still argued that an n:m threading library would be a possibility (of which the early 1:m implementations of POSIX threads were just a special case).十年前,人们仍然认为 n:m 线程库是一种可能性(其中 POSIX 线程的早期 1:m 实现只是一个特例)。

But today, programmers call unshare (CLONE_FS) from a thread to give that thread a private current directory, separate from all the other threads.但是今天,程序员从一个线程调用unshare (CLONE_FS)来为该线程提供一个私有的当前目录,与所有其他线程分开。 They call setfscreatecon and expect that this only affects the calling thread.他们调用setfscreatecon并期望这只会影响调用线程。 They even call the system calls setresuid and setresgid directly because they want to avoid the setxid broadcast that glibc uses to propagate the change to all threads (something that the kernel does not support directly).他们甚至直接调用系统调用setresuidsetresgid因为他们想避免 glibc 用来将更改传播到所有线程的 setxid 广播(内核不直接支持的东西)。 All this would stop working under an n:m threading model.所有这些都将在 n:m 线程模型下停止工作。 So std::thread and POSIX threads would have to map to kernel tasks, enforcing the 1:1 model.所以std::thread和 POSIX 线程必须映射到内核任务,强制执行 1:1 模型。

In addition, there is just one GNU TLS ABI for both C and C++, and that in turn pretty much requires that there can only be one type of thread in the system, with one thread pointer that is used to eventually reach thread-local data.此外,C 和 C++ 都只有一个 GNU TLS ABI,这反过来又要求系统中只能有一种类型的线程,一个线程指针用于最终访问线程本地数据.

That's why it's so unlikely that on GNU/Linux, std::thread will ever use anything but the POSIX threads provided by glibc.这就是为什么在 GNU/Linux 上, std::thread不太可能使用 glibc 提供的 POSIX 线程以外的任何东西的原因。

The correct way is to set the required signal mask in the parent before creating a thread and then revert it in the parent.正确的方法是创建线程之前在父级中设置所需的信号掩码,然后在父级中将其还原。 This way your newly created thread has the correct signal mask set from its very start.这样,您新创建的线程从一开始就设置了正确的信号掩码。 (The signal mask is inherited from the parent thread). (信号掩码是从父线程继承的)。

When you set the signal mask after the thread has started, there is a window of time during which the thread doesn't have the required mask.在线程启动设置信号掩码时,有一个时间窗口,在此期间线程没有所需的掩码。

If your need to set the signal mask in a multithreaded program on a POSIX system, then pthread_sigmask is the function that you need to use.如果您需要在 POSIX 系统上的多线程程序中设置信号掩码,那么pthread_sigmask就是您需要使用的函数。 There are no functions to interact with signal masks in the C++ standard library. C++ 标准库中没有与信号掩码交互的函数。

Also, I believe the effect of pthread_sigmask(SIG_BLOCK, &mask, NULL) will only apply to the thread created using ...另外,我相信pthread_sigmask(SIG_BLOCK, &mask, NULL)仅适用于使用 ...

pthread_sigmask applies to the thread in which the call was executed, regardless of how the thread has been created. pthread_sigmask适用于执行调用的线程,而不管线程是如何创建的。 It applies to no other pre-existing threads.它不适用于其他预先存在的线程。 In the case of your example, the function rotate_log in which pthread_sigmask is called is executed in the thread created by std::thread .在您的示例中,调用pthread_sigmask的函数rotate_logstd::thread创建的std::thread

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM