将 sigwait 与 std::thread 和管道一起使用
Using sigwait with std::thread and pipe
考虑一个包含多个工作线程的并行程序。这些线程在某些文件描述符上有一个 poll
循环。该程序应该 运行 直到按下 ctrl-c / 进程接收到 SIGINT
。程序不应该被不必要地唤醒。
我设计了以下 sigwait
、std::thread
、pipe
和 pthread_sigmask
的组合。请注意,在实际应用程序中,有更多的文件描述符,因此我没有使用原子来关闭线程。
#include <thread>
#include <iostream>
#include <cstdlib>
#include <csignal>
extern "C" {
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
}
int fds[2];
void thread_run() {
struct pollfd pfd = {fds[0], POLLIN, 0};
int ret = poll(&pfd, 1, -1);
if (ret != 1) std::terminate();
if (!pfd.revents & POLLIN) std::abort();
}
int main()
{
int ret = pipe(fds);
if (ret) std::abort();
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGINT);
ret = pthread_sigmask(SIG_BLOCK, &ss, NULL);
if (ret) std::abort();
std::thread t(thread_run);
int sig;
ret = sigwait(&ss, &sig);
if (ret) std::abort();
char b = 0;
ret = write(fds[1], &b, 1);
if (ret != 1) std::abort();
t.join();
close(fds[0]);
close(fds[1]);
}
该程序似乎可以正常运行。
- 这种方法是否符合要求,还是我忽略了任何注意事项?
- 是否有任何特定的错误情况可能会在正常操作中发生
并且可以更优雅地处理?
- 如果我交换
std::thread
-creation 和 pthread_sigmask
程序是否仍然正确?
- 这是一种标准的推荐方法,效果很好。请参阅 pthread_sigmask 中的示例部分。
- 找不到任何东西。
- 这是不正确的。大多数信号都是特定于进程的,这意味着它们会被传送到进程中不会阻塞该信号的任何线程。因此,该信号必须在除处理该信号的线程之外的所有线程中被阻塞。
您可能喜欢在意外情况下使用 std::abort
调用。 std::terminate
在异常处理失败时由 C++ 运行时调用。
考虑一个包含多个工作线程的并行程序。这些线程在某些文件描述符上有一个 poll
循环。该程序应该 运行 直到按下 ctrl-c / 进程接收到 SIGINT
。程序不应该被不必要地唤醒。
我设计了以下 sigwait
、std::thread
、pipe
和 pthread_sigmask
的组合。请注意,在实际应用程序中,有更多的文件描述符,因此我没有使用原子来关闭线程。
#include <thread>
#include <iostream>
#include <cstdlib>
#include <csignal>
extern "C" {
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
}
int fds[2];
void thread_run() {
struct pollfd pfd = {fds[0], POLLIN, 0};
int ret = poll(&pfd, 1, -1);
if (ret != 1) std::terminate();
if (!pfd.revents & POLLIN) std::abort();
}
int main()
{
int ret = pipe(fds);
if (ret) std::abort();
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGINT);
ret = pthread_sigmask(SIG_BLOCK, &ss, NULL);
if (ret) std::abort();
std::thread t(thread_run);
int sig;
ret = sigwait(&ss, &sig);
if (ret) std::abort();
char b = 0;
ret = write(fds[1], &b, 1);
if (ret != 1) std::abort();
t.join();
close(fds[0]);
close(fds[1]);
}
该程序似乎可以正常运行。
- 这种方法是否符合要求,还是我忽略了任何注意事项?
- 是否有任何特定的错误情况可能会在正常操作中发生 并且可以更优雅地处理?
- 如果我交换
std::thread
-creation 和pthread_sigmask
程序是否仍然正确?
- 这是一种标准的推荐方法,效果很好。请参阅 pthread_sigmask 中的示例部分。
- 找不到任何东西。
- 这是不正确的。大多数信号都是特定于进程的,这意味着它们会被传送到进程中不会阻塞该信号的任何线程。因此,该信号必须在除处理该信号的线程之外的所有线程中被阻塞。
您可能喜欢在意外情况下使用 std::abort
调用。 std::terminate
在异常处理失败时由 C++ 运行时调用。