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

C_u*_*er5 2 c++ multithreading signals pthreads stdthread

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();
Run Code Online (Sandbox Code Playgroud)

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();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Max*_*kin 5

正确的方法是在创建线程之前在父级中设置所需的信号掩码,然后在父级中恢复它。这样,您新创建的线程从一开始就具有正确的信号掩码集。(信号掩码是从父线程继承的)。

当您在线程启动后设置信号掩码时,会有一段时间窗口,在此期间线程没有所需的掩码。

  • @SoulfreezerXP 被阻止的信号保持待定状态并且不会丢失。当信号被解除阻塞时,挂起的信号将被传递到信号处理程序,可以将其设置为“SIG_IGN”以忽略该信号。换句话说,您不会意外错过信号。该手册页详细解释了它,并且是权威来源,与我不同。 (2认同)

Flo*_*mer 5

从理论上讲,std::thread即使在具有POSIX线程的系统上,的实现也可能会创建非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线程以外的任何东西的可能性很小。

  • 在 Linux 上,还可以使用 [signalfd](http://man7.org/linux/man-pages/man2/signalfd.2.html) 以*更好* 的方式处理信号。 (2认同)