gpt4 book ai didi

c - pselect 通知两个管道读端文件描述符,即使只有一个写端被写入

转载 作者:太空宇宙 更新时间:2023-11-04 03:25:11 32 4
gpt4 key购买 nike

我无法理解 pselect 的行为。基本上我做的是以下内容:

  • 为 SIGCHILD 信号注册一个处理程序
  • 创建两个管道
  • 使用fork 创建一个子进程
  • 让 child 睡5秒,然后退出
  • 在父进程调用pselect,等待两个管道的读端
  • 当子进程终止时,在 SIGCHILD 处理程序中的第一个管道中写入一些内容。
  • pselect 在父进程中返回并设置了两个文件描述符

我希望以下代码的输出是:

Pipe1 is set!

但是,我得到的是:

Pipe1 is set!
Pipe2 is set!

当我只在一个管道写入端写入时,为什么两个管道读取端文件描述符都被设置了?此行为是正常 pselect 虚假文件描述符通知的一部分吗?我究竟做错了什么?

程序如下:

    #include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<iostream>

enum PipeEnd {
READ_END = 0, WRITE_END = 1, MAX_END
};

int pipe1[MAX_END], pipe2[MAX_END];

void handle_sigchld(const int signal) {
//In the SIGCHLD handler write the process ID on pipe1
int returnStatus;
int childPID = waitpid(static_cast<pid_t>(-1), &returnStatus, WNOHANG);
write(pipe1[WRITE_END], &childPID, sizeof(childPID));
}

void createPipe(int newPipe[MAX_END]) {
pipe(newPipe);
fcntl(newPipe[READ_END], F_SETFL, O_NONBLOCK);
fcntl(newPipe[WRITE_END], F_SETFL, O_NONBLOCK);
}

int main(int argc, const char** argv) {
//Add a handler for the SIGCHLD signal
struct sigaction sa;
sa.sa_handler = &handle_sigchld;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
sigaction(SIGCHLD, &sa, nullptr);

//Create two pipes
createPipe(pipe1);
createPipe(pipe2);

//Create a child process
if (0 == fork()) {
sleep(5);
exit(0);
}

fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(pipe1[READ_END], &read_fds);
FD_SET(pipe2[READ_END], &read_fds);
int maxfd = std::max(pipe1[READ_END], pipe2[READ_END]);
//Wait for a file descriptor to be notified
pselect(maxfd + 1, &read_fds, nullptr, nullptr, nullptr, nullptr);

//Check if the read ends of the two pipes are set/notified
if (FD_ISSET(pipe1[READ_END], &read_fds))
std::cout << "Pipe1 is set!" << std::endl;
if (FD_ISSET(pipe2[READ_END], &read_fds))
std::cout << "Pipe2 is set!" << std::endl;
return 0;
}

最佳答案

即使信号处理程序没有写入任何内容,程序也会表现出相同的行为,这会让您感到惊讶。

原因是pselect失败了。引用 man 7 signal,

The following interfaces are never restarted after being interrupted by a signal handler, regardless of the use of SA_RESTART; they always fail with the error EINTR when interrupted by a signal handler:

....

  • File descriptor multiplexing interfaces: epoll_wait(2), epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).

始终测试系统调用返回的内容。

关于c - pselect 通知两个管道读端文件描述符,即使只有一个写端被写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41742908/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com