Полезно ли вызывать pthread_sigmask в потоке, созданном 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();
}
}
}
3 ответа
Теоретически возможно, что реализация std::thread
создаст поток, отличный от POSIX, даже в системе, в которой есть потоки POSIX, и pthread_sigmask
не будет работать для таких тем. ( Комментарий Максима Егорушкина верен - вам действительно следует блокировать потоки в потоке, создающем поток, и разблокировать только те, которые вы хотите обработать в новом потоке, чтобы избежать условий гонки.)
Я не могу говорить о других реализациях, но крайне маловероятно, что такое случится для реализации GNU/Linux. Конечно, я не могу говорить авторитетно и для этой реализации, но там просто слишком много кода на C и C++, который предполагает отображение 1:1 между потоками пространства пользователя (будь то C, C++ или POSIX) и задачами ядра (те вещи, которые есть TID). Десять лет назад люди все еще утверждали, что возможна библиотека потоков n:m (из которых ранние реализации потоков POSIX 1: m были просто особым случаем).
Но сегодня программисты называют unshare (CLONE_FS)
из потока, чтобы дать этому потоку частный текущий каталог, отдельный от всех других потоков. Они звонят setfscreatecon
и ожидать, что это влияет только на вызывающий поток. Они даже вызывают системные вызовы setresuid
а также setresgid
напрямую, потому что они хотят избежать широковещательной рассылки setxid, которую использует glibc для распространения изменений на все потоки (то, что ядро не поддерживает напрямую). Все это перестало бы работать в поточной модели n:m. Так std::thread
и потоки POSIX должны будут сопоставляться с задачами ядра, применяя модель 1:1.
Кроме того, существует только один GNU TLS ABI как для C, так и для C++, и это, в свою очередь, в значительной степени требует, чтобы в системе был только один тип потока, с одним указателем потока, который используется для достижения локальных данных потока,
Вот почему это так маловероятно, что в GNU/Linux, std::thread
будет когда-либо использовать что-либо кроме потоков POSIX, предоставляемых glibc.
Правильный способ - установить требуемую маску сигнала в родительском элементе перед созданием потока, а затем вернуть его в родительский. Таким образом, ваш вновь созданный поток имеет правильную маску сигналов, установленную с самого начала. (Маска сигнала наследуется от родительского потока).
Когда вы устанавливаете маску сигнала после запуска потока, появляется окно времени, в течение которого поток не имеет требуемой маски.
Если вам необходимо установить маску сигнала в многопоточной программе в системе POSIX, то pthread_sigmask
это функция, которую вам нужно использовать. В стандартной библиотеке C++ нет функций для взаимодействия с масками сигналов.
Кроме того, я считаю, что эффект
pthread_sigmask(SIG_BLOCK, &mask, NULL)
будет применяться только к теме, созданной с помощью...
pthread_sigmask
применяется к потоку, в котором был выполнен вызов, независимо от того, как был создан поток. Это не относится ни к каким другим ранее существующим потокам. В случае вашего примера, функция rotate_log
в котором pthread_sigmask
вызывается выполняется в потоке, созданном std::thread
,