2012-05-12 143 views
3

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

} 

回答

3

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

这可能是不明智的关闭文件描述符,而他们可能会在 通过使用在同一过程中的其他线程的系统调用。由于 文件描述符可能会被重复使用,有一些模糊的竞争条件 可能会导致意想不到的副作用。

既然你是在Linux上,你可以做到以下几点:

  • 搭建eventfd并将其添加到投票
  • 信号的eventfd(写入)当你想关闭FD
  • 在调查中,当你看到在eventfd活动,你可以立即关闭一个fd和从poll
删除

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


既然你是在Linux上,你可能要考虑epoll为上级尽管非标准替代poll

+0

谢谢,该片段正是我应该读过:)重复使用会导致我的问题。我无法写信给自己,因为它会连接到远程,所以我不得不提出自定义信号。 –

相关问题