当一个进程的输出被管道输送到另一个进程时,我试图实现它的优雅关闭。我正在测试下面的代码,它的输出是:./a.out | less,并在出现提示符时按下q。我看到的不是sigwait()的预期完成,而是信号处理程序的调用(这里添加它只是为了显示正在发生的事情)。
#include <csignal>
#include <chrono>
#include <iostream>
#include <thread>
#include <signal.h>
int handlerSig {0};
void signalHandler(int s)
{
handlerSig = s;
std::cerr << "handlerSig: " << handlerSig << std::endl;
}
int main()
{
for (int i = 1; i < 32; ++i)
{
std::signal(i, signalHandler);
}
bool run {true};
std::thread thread {[&]
{
while (run)
{
std::cout << "ping" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds {500});
}
}};
sigset_t waitSet;
sigemptyset(&waitSet);
sigaddset(&waitSet, SIGINT);
sigaddset(&waitSet, SIGPIPE);
sigaddset(&waitSet, SIGTERM);
pthread_sigmask(SIG_BLOCK, &waitSet, nullptr);
int waitSig {0};
sigwait(&waitSet, &waitSig);
run = false;
thread.join();
std::cerr << "waitSig: " << waitSig << std::endl;
}我在WSL2和CentOS机器上得到了一致的结果,我更愿意集中精力解决这个问题。在WSL1下运行时,除非我删除pthread_sigmask(SIG_BLOCK...),否则SIGINT或SIGTERM都不会导致sigwait()的完成,但这似乎与我对如何使用sigwait()的理解相矛盾。
发布于 2021-02-22 15:15:08
您需要想出其他方法来注意写入失败,例如,忽略SIGPIPE但设置std::cout.exceptions(ios::badbit),或者在写入线程中处理信号。
重要的是,SIGPIPE将始终为您的写入线程生成,尽管您的sigwait()正在执行线程。从线程的活动中产生的某些信号只为该线程生成,这意味着它们将仅被传递到该线程或被该线程接受。(POSIX.1-2008 2.4.1)通常,“自然发生”的SIGPIPE、SIGFPEs和SIGSEGV都是这样工作的。
发布于 2021-02-22 16:32:57
这是将SIGPIPE转发到主线程的一个示例--在我的情况下可能就足够了:
#include <csignal>
#include <chrono>
#include <iostream>
#include <thread>
#include <signal.h>
pthread_t mainThread {pthread_self()};
void forwardSig(int sig)
{
if (not pthread_equal(pthread_self(), mainThread))
{
pthread_kill(mainThread, sig);
}
}
int main()
{
struct sigaction newAction {};
sigemptyset(&newAction.sa_mask);
newAction.sa_handler = forwardSig;
sigaction(SIGPIPE, &newAction, nullptr);
bool run {true};
std::thread thread {[&]
{
while (run)
{
std::cout << "ping" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds {500});
}
}};
sigset_t waitSet;
sigemptyset(&waitSet);
sigaddset(&waitSet, SIGINT);
sigaddset(&waitSet, SIGPIPE);
sigaddset(&waitSet, SIGTERM);
pthread_sigmask(SIG_BLOCK, &waitSet, nullptr);
int waitSig {0};
sigwait(&waitSet, &waitSig);
run = false;
thread.join();
std::cerr << "waitSig: " << waitSig << std::endl;
}https://stackoverflow.com/questions/66316244
复制相似问题