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

时间:2019-02-25 16:54:37

标签: c++ multithreading pthreads signals stdthread

1)我是std :: thread的新手,我想知道调用UIApplication.shared.sendAction(#selector(UIResponder.resign‌​FirstResponder), to: nil, from: nil, for: nil) 来阻止由创建的特定线程中的某些信号是否是一个好习惯pthread_sigmask()

我不希望新线程接收SIGTERM,SIGHUP等信号,因为主进程已经安装了这些信号的处理程序。

那么,调用std::thread来阻止pthread_sigmask()创建的线程中的某些信号是一种好习惯吗?

2)另外,我相信std::thread的作用仅适用于使用

创建的线程
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()

3 个答案:

答案 0 :(得分:4)

理论上,即使在具有POSIX线程的系统上,std::thread的实现也可能会创建非POSIX线程,而pthread_sigmask不适用于此类线程。 (不过,{Maxim Egorushkin's comment是正确的,您确实应该在创建线程的线程中阻塞线程,而仅取消阻塞要在新线程上处理的线程,以避免出现竞争情况。)

我不能代表其他实现,但是极端对于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线程之外几乎不会使用任何东西的原因。

答案 1 :(得分:2)

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

在线程启动之后设置信号掩码 时,线程会在一段时间内没有所需的掩码。

答案 2 :(得分:1)

如果需要在POSIX系统上的多线程程序中设置信号掩码,那么pthread_sigmask是您需要使用的功能。 C ++标准库中没有与信号掩码交互的功能。

  

此外,我相信pthread_sigmask(SIG_BLOCK, &mask, NULL)的作用仅适用于使用...创建的线程。

pthread_sigmask适用于在其中执行调用的线程,而不管其创建方式如何。它不适用于其他任何现有线程。在您的示例中,在rotate_log创建的线程中执行了调用pthread_sigmask的函数std::thread