通过关闭socketpair在默认Ubuntu上没有SIGHUP



一旦父类关闭管道,下面的代码应该调用信号处理程序。信号处理程序将被子进程触发,因为它等待一秒钟。此等待周期应由信号处理程序中断。

只输出:

n=10, 'Hello Worl'  // perfect line ;), but the next line is missing.
// "signal received: ...  MISSING

无论如何,信号处理程序不会被调用。有人知道为什么吗?

提示:由于没有信号被处理,子进程被留下。手动终止

#include <csignal>
#include <cstdio>
#include <sys/socket.h>
#include <unistd.h>
void child(int socket) {
while (true) {
char buf[100];
int n = read(socket, buf, 10);
printf("n=%d, '%s'n", n, buf);
sleep(1);
}
}
void parent(int socket) {
char buf[] = "Hello Worldn";
write(socket, buf, sizeof(buf));
close(socket);
}
int main() {
int socket[2];
socketpair(AF_LOCAL, SOCK_DGRAM, 0, socket);
signal(SIGHUP, [](int sig) {
printf("signal received: %dn", sig);
});
switch (fork()) {
case 0:
close(socket[1]);
child(socket[0]);
break;
default:
close(socket[0]);
parent(socket[1]);
break;
case -1:
return 1;
}
return 0;
}

的意图是,如果一方死亡,套接字对在term中被破坏,这应该引起某种信号,这应该导致所有启动的进程崩溃

好吧,在这种情况下,数据报套接字是你唯一不能使用的东西。

如果你想继续使用文件描述符和/或保持完全的posix兼容,流套接字或管道是你可以使用的。

#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
// using socketpair
#include <unistd.h>
// using fork, sleep, close
#include <cstdio>
// using std::puts

int main()
{
int sockets[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
if(fork()) { // parent
close(sockets[1]);
sleep(1);
std::puts("Parent exit");
}
else { // child
close(sockets[0]);
pollfd poll_fd = { sockets[1], POLLIN, 0 };
poll(&poll_fd, 1, 2000 /*timeout*/);
if(poll_fd.revents & POLLIN)
std::puts("Parent died before child");
else
std::puts("Child exit before parent");
}
}

就我个人而言,如果我不需要套接字,我就使用管道,在父进程中保持写端打开,在子进程中保持读端打开。当写端关闭时(或者在流套接字上,如果任何一方关闭),读取将解除阻塞(指示EOF)。

如果你有某种事件循环,这种方法是最有用的,因为你通常可以把它插入那些,就像我在这里对poll所做的那样。如果你不这样做,你想要一个信号,你可以使用SIGIO和中断驱动的输入,但我发现这相当乏味,特别是对于较大的进程树。

如果您喜欢特定于linux的解决方案,那么prctl(PR_SET_PDEATHSIG, SIGHUP)就是您想要的。

#include <sys/types.h>
#include <unistd.h>
// using getpid, getppid, pause, sleep
#include <sys/prctl.h>
#include <csignal>
#include <cstdio>
// using std::puts. std::printf
#include <cstring>
// using std::strlen

int main()
{
pid_t parent_id = getpid();
if(fork()) { // parent
sleep(1);
std::puts("Parent exit");
}
else { // child
std::signal(SIGHUP, [](int sig) {
const char* msg = "Child received SIGHUPn";
// puts or printf are not signal-safe
write(1 /*stdout*/, msg, std::strlen(msg));
_exit(1); // std::exit is not signal-safe!
});
prctl(PR_SET_PDEATHSIG, SIGHUP);
if(getppid() != parent_id) {
std::puts("Parent died during child setup");
return 0;
}
while(true)
pause();
}
}

注意这个来自手册页的警告:

"parent"在本例中,被认为是创建此进程的线程。换句话说,该信号将在该线程终止时(例如通过pthread_exit(3))发送,而不是在父进程中的所有线程终止后发送。

BTW:您在信号处理程序中使用printf是错误的。没有一个C studio函数是异步信号安全的。

最新更新