linux - 关闭正在轮询的文件描述符

标签 linux pthreads file-descriptor

如果我有两个线程(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;

}

最佳答案

至少对于 Linux 来说,这似乎是有风险的。 close 的手册页警告:

It is probably unwise to close file descriptors while they may be in use by system calls in other threads in the same process. Since a file descriptor may be reused, there are some obscure race conditions that may cause unintended side effects.

由于您使用的是 Linux,您可以执行以下操作:

  • 设置一个eventfd并将其添加到投票中
  • 当你想关闭一个 fd 时向 eventfd 发送信号(写入它)
  • 在轮询中,当您在 eventfd 上看到事件时,您可以立即关闭 fd 并将其从 poll
  • 中删除

或者,您可以简单地建立一个signal 处理程序并在poll 返回时检查errno == EINTR。信号处理程序只需要将一些全局变量设置为您要关闭的 fd 的值。


由于您使用的是 Linux,您可能需要考虑 epoll作为 poll 的非标准替代方案。

关于linux - 关闭正在轮询的文件描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10561602/

相关文章:

linux - angular2 cli 安装出错

c++ - 将 Qt 添加到 C-Socket 程序中?

c - 不仅仅是线程之间的数据通信

linux - 最大套接字描述符值

linux - 模式匹配日志文件

linux - 在 shell 中以其他用户身份运行时无法初始化变量

linux - 查看哪些 http 页面正在通过 SSH 访问(实时)?

c - pthread_create 后跟 pthread_detach 仍然会导致 Valgrind 中可能丢失错误

bash - 文件描述符权限被 bash 进程替换拒绝?

c++ - 如何在不创建新 int 的情况下设计 RAII 文件描述符