gpt4 book ai didi

c - 为什么 EPOLLOUT 会改变 EPOLLIN 的处理方式?

转载 作者:太空狗 更新时间:2023-10-29 11:21:40 25 4
gpt4 key购买 nike

关于事件是否合并的文档并不清楚,我的测试表明它们在某些情况下存在,但并非总是如此。

考虑 man 7 epoll:

Since even with edge-triggered epoll, multiple events can be generated upon receipt of multiple chunks of data, the caller has the option to specify the EPOLLONESHOT flag...

和问答部分:

Q7 If more than one event occurs between epoll_wait(2) calls, are they combined or reported separately?

A7 They will be combined.

我假设手册中的第一个语句意味着在从套接字读取数据包到达,您读取它,然后另一个数据包到达等情况下,您可以接收多个 EPOLLIN 事件。问答部分的答案是谈论不同的事件,如 EPOLLIN 和 EPOLLOUT。如果我错了,请纠正我。

我正在研究一些代码,以便更好地理解 epoll 的工作原理,它似乎根据是否设置了另一个事件而对同一类型的事件表现不同。更准确地说,如果我只等待 EPOLLIN,多个输入将生成一个事件,但如果我同时等待 EPOLLIN 和 EPOLLOUT,则多个输入将生成多个事件。

这是我用来测试的代码:

#include <stdio.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
struct epoll_event ev = {EPOLLIN|EPOLLOUT|EPOLLET};
int epoll = epoll_create1(0);
epoll_ctl(epoll, EPOLL_CTL_ADD, 0, &ev);

//async stdin
int flags = fcntl(0, F_GETFL);
flags |= O_NONBLOCK;
fcntl(0, F_SETFL, flags);

while(1){
struct epoll_event events[64];
int n = epoll_wait(epoll, events, 64, -1);

printf("Event count: %d\n", n);

if(events[0].events == EPOLLIN)
printf("EPOLLIN only\n\n");

else
if(events[0].events == (EPOLLIN|EPOLLOUT))
printf("EPOLLIN and EPOLLOUT\n\n");

else
printf("EPOLLOUT only\n\n");

char buffer[256];
read(0, buffer, 256);

sleep(1);
}
return 0;
}

按下回车后的输出显示同时收到了 EPOLLIN 和 EPOLLOUT,此消息出现的次数与按下回车的次数相同,然后显示仅生成了 EPOLLOUT。

但是如果不带EPOLLOUT标志编译程序,多次回车,单个事件只会报一次。

如果我删除 read 调用,则在设置 EPOLLOUT 时会继续报告 EPOLLIN,但在仅设置 EPOLLIN 时则不会。

行为是否取决于它正在等待的事件或我的测试代码有问题?如果是依赖,我能保证以后不会变吗?

最佳答案

我相信您正在观察未定义行为的影响,因为您在滥用 API。

具体来说,您正在将 STDIN_FILENO(即 0)传递给 epoll_ctl 并要求等待 EPOLLOUT在只读的文件描述符上。可能发生的情况是操作系统试图告诉您文件描述符的写入方向有问题。

另外,当使用边缘触发模式时,您应该继续您的 I/O,直到您看到 EAGAIN。当操作不再阻塞时,epoll_wait 调用返回。

我修改了您的程序以改为使用套接字,并从套接字读取数据直到 EAGAIN,它的行为符合我的预期。

在我的版本中,我创建了一对套接字,以及一个从 STDIN_FILENO 读取并写入一对套接字之一的线程。 main 主体循环然后在另一个套接字上执行 epoll_wait

当我启动程序时,它会在第一次调用 epoll_wait 时返回以报告可写,但会在下一次迭代时阻塞:

Event count: 1
EPOLLOUT only

当我键入输入时,它报告可读和可写,然后在下一次迭代中阻塞 epoll_wait,正如预期的那样:

asdf
Event count: 1
EPOLLIN and EPOLLOUT

我使用的代码如下。一、线程:

static void * iothread (void *svp) {
int *sv = svp;
char buf[256];
ssize_t r;
again:
while ((r = read(0, buf, sizeof(buf))) > 0) {
ssize_t n = r;
const char *p = buf;
while (n > 0) {
r = write(sv[1], p, n);
if (r < 0) {
if (errno == EINTR) continue;
break;
}
n -= r;
p += r;
}
if (n > 0) break;
}
if (r < 0 && errno == EINTR) {
goto again;
}
close(sv[1]);
return NULL;
}

然后,主体主体:

int main(int argc, char* argv[]) {
int sv[2];
struct epoll_event ev = {EPOLLIN | EPOLLOUT | EPOLLET};
int epoll = epoll_create1(0);
pthread_t t;

socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
pthread_create(&t, NULL, iothread, sv);
epoll_ctl(epoll, EPOLL_CTL_ADD, sv[0], &ev);
while(1){
struct epoll_event events[64];
int n = epoll_wait(epoll, events, 64, -1);

printf("Event count: %d\n", n);

if(events[0].events == EPOLLIN)
printf("EPOLLIN only\n\n");
else
if(events[0].events == (EPOLLIN|EPOLLOUT))
printf("EPOLLIN and EPOLLOUT\n\n");
else
printf("EPOLLOUT only\n\n");

char buffer[256];
ssize_t r;
again:
r = recv(sv[0], buffer, 256, MSG_DONTWAIT);
if (r > 0) goto again;
if (r < 0 && errno == EAGAIN) {
sleep(1);
continue;
}
break;
}
return 0;
}

关于c - 为什么 EPOLLOUT 会改变 EPOLLIN 的处理方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36302580/

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