关闭正在进行轮询的文件描述符

4
如果我有两个线程(Linux,NPTL),其中一个正在轮询一个或多个文件描述符,另一个正在关闭其中一个文件描述符,这是合理的行为吗?我在MT环境中做了一些不应该做的事情吗?
我考虑这样做的主要原因是,我不必与轮询线程通信、中断它等,我只想出于任何原因关闭描述符,并且当轮询线程唤醒时,我希望revents包含POLLNVAL,这将表明下一次轮询前线程应该丢弃文件描述符。
我已经编写了一个简单的测试,确实显示POLLNVAL正是会发生的情况。然而,在这种情况下,只有当超时到期时才设置POLLNVAL,关闭套接字似乎不使poll()返回。如果是这样,我可以杀死线程使poll()重新启动并返回。
#define _GNU_SOURCE

#include <stdio.h>
#include <pthread.h>
#include <poll.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

static pthread_t main_thread;

void * close_some(void*a) {

    printf("thread #2 (%d) is sleeping\n", getpid());
    sleep(2);
    close(0);
    printf("socket closed\n");
    // comment out the next line to not forcefully interrupt
    pthread_kill(main_thread, SIGUSR1);
    return 0;

}

void on_sig(int s) {
    printf("signal recieved\n");
}

int main(int argc, char ** argv) {

    pthread_t two;
    struct pollfd pfd;
    int rc;

    struct sigaction act;
    act.sa_handler = on_sig;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGUSR1, &act, 0);

    main_thread = pthread_self();

    pthread_create(&two, 0, close_some, 0);

    pfd.fd = 0;
    pfd.events = POLLIN | POLLRDHUP;

    printf("thread 0 (%d) polling\n", getpid());

    rc = poll(&pfd, 1, 7000);

    if (rc < 0) {
        printf("error : %s\n", strerror(errno));
    } else if (!rc) {
        printf("time out!\n");
    } else {
        printf("revents = %x\n", pfd.revents);
    }
    return 0;

}
1个回答

7
至少对于 Linux 系统而言,这似乎是有风险的。在 close 的手册页面中有警告:

当文件描述符可能正在被同一进程中其他线程的系统调用使用时,关闭文件描述符可能是不明智的。由于文件描述符可能会被重用,因此存在一些难以理解的竞争条件,可能会导致意外的副作用。

既然你正在使用 Linux,你可以采取以下措施:
  • 设置一个 eventfd 并将其添加到轮询中
  • 当你想要关闭一个 fd 时,向 eventfd 发送信号(写入数据)
  • 在轮询中,当你看到 eventfd 上有活动时,你可以立即关闭 fd 并将其从轮询中删除
或者你也可以简单地建立一个 signal 处理程序,并在 poll 返回时检查 errno == EINTR。信号处理程序只需要将某个全局变量设置为你正在关闭的 fd 的值即可。
既然你正在使用 Linux,你可能会考虑使用epoll作为一种优秀但非标准的 poll 替代方法。

谢谢,那段代码片段正是我应该阅读的内容 :) 可重用性会给我带来问题。我无法自己写入fd,因为它将连接到远程,所以我必须想出自定义信号传递的方法。 - Pawel Veselov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接