2012-05-12 3 views
3

2つのスレッド(Linux、NPTL)があり、1つまたは複数のファイルディスクリプタでポーリングしているスレッドが1つあり、そのうちの1つが閉じている場合は、アクション? 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を設定し、

  • 世論調査に追加

    • をあなたはeventfd上での活動を見ると、すぐにFDを閉じてpoll
    から削除することができ、世論調査では、FD
  • を閉じます

    signalハンドラを設定し、pollが返されたときにerrno == EINTRを確認するだけで済みます。シグナルハンドラは、あなたが閉じているfdの値にいくつかの大域変数をセットするだけでよいでしょう。あなたは、Linuxにしているので


    あなたはpollに非標準の代替とはいえ、優れたとしてepollを検討する必要があります。

  • +0

    ありがとう、そのスニペットは私が読んだはずのものです:)再利用可能性は私に問題を引き起こすでしょう。私はfdに自分自身を書くことはできません。それはリモートに接続されるので、私はカスタムシグナリングを考えなければなりません。 –