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
.
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.
So, is it a good practice to call pthread_sigmask()
to block some signals in a thread created by std::thread
?
2) Also, I believe the effect of pthread_sigmask(SIG_BLOCK, &mask, NULL)
will only apply to the thread created using
std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach();
and calling rotate_log()
as the start function.
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.
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. (Maxim Egorushkin's comment is correct, though—you really should block threads in the thread-creating thread and only unblock those you want handled on the new thread, to avoid race conditions.)
I cannot speak for other implementations, but it it is extremely unlikely that such a thing will happen for the GNU/Linux implementation. 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). 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).
But today, programmers call unshare (CLONE_FS)
from a thread to give that thread a private current directory, separate from all the other threads. They call setfscreatecon
and expect that this only affects the calling thread. 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). All this would stop working under an n:m threading model. So std::thread
and POSIX threads would have to map to kernel tasks, enforcing the 1:1 model.
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.
That's why it's so unlikely that on GNU/Linux, std::thread
will ever use anything but the POSIX threads provided by glibc.
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. There are no functions to interact with signal masks in the C++ standard library.
Also, I believe the effect of pthread_sigmask(SIG_BLOCK, &mask, NULL)
will only apply to the thread created using ...
pthread_sigmask
applies to the thread in which the call was executed, regardless of how the thread has been created. 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
.