在 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 的东西)之间有 1:1 的映射。 十年前,人们仍然认为n:m线程库是一种可能性(POSIX线程的早期1:m实现只是一个特例)。
但是今天,程序员从线程调用unshare (CLONE_FS)
,为该线程提供一个专用的当前目录,与所有其他线程分开。 他们调用setfscreatecon
并期望这只影响调用线程。 他们甚至直接调用系统调用setresuid
和setresgid
,因为他们想避免 glibc 用来将更改传播到所有线程的 setxid 广播(内核不直接支持)。 所有这些都将在 n:m 线程模型下停止工作。 因此,std::thread
和 POSIX 线程必须映射到内核任务,强制执行 1:1 模型。
此外,C 和 C++ 只有一个 GNU TLS ABI,这反过来又要求系统中只能有一种类型的线程,其中一个线程指针用于最终访问线程本地数据。
这就是为什么在GNU/Linux上,除了glibc提供的POSIX线程之外,std::thread
不太可能使用任何东西。
正确的方法是在创建线程之前在父级中设置所需的信号掩码,然后在父级中将其还原。这样,您新创建的线程从一开始就设置了正确的信号掩码。(信号掩码继承自父线程)。
在线程启动后设置信号掩码时,有一个时间段,在此期间线程没有所需的掩码。
如果您需要在POSIX系统上的多线程程序中设置信号掩码,那么pthread_sigmask
是您需要使用的功能。C++标准库中没有与信号掩码交互的函数。
另外,我相信
pthread_sigmask(SIG_BLOCK, &mask, NULL)
的效果仅适用于使用...
pthread_sigmask
适用于在其中执行调用的线程,而不管线程是如何创建的。它不适用于其他预先存在的线程。在您的示例中,调用pthread_sigmask
的函数rotate_log
在std::thread
创建的线程中执行。
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 有没有一种方法可以在编译时获得作用域类名
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 一种在C++中读取TXT配置文件的简单方法
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 在调用接收数组的方法时,模板化数组大小是不是一种糟糕的做法
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 将错误返回给调用方而不是立即在 C++ 中抛出错误是否是一种好的做法
- 在 c++ 中,有一种方法可以创建一个包含地图作为值的树状地图?
- 有没有一种优雅而快速的方法来测试整数中的 1 位是否位于连续区域
- 在运行时检查继承是否只有一种类型和 void*
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 找到一种有效的方法,在 2 个巨大的缓冲区上执行 MAX,每字节字节
- 寻找一种更好的方法来表示无符号字符数组
- 我正在寻找一种优雅的方式来从元组向量创建tuple_element向量