4

2つのスレッド(Linux、NPTL)があり、1つ以上のファイル記述子をポーリングしているスレッドが1つあり、もう1つがそれらの1つを閉じている場合、それは妥当なアクションですか?MT環境でやるべきではないことをやっていますか?

私がそうすることを検討する主な理由は、必ずしもポーリングスレッドと通信したり、中断したりする必要がないためです。代わりに、何らかの理由で記述子を閉じたいだけです。ポーリングスレッドが起動すると、リベントには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;

}
4

1 に答える 1

6

少なくとも Linux では、これは危険に思えます。close警告のマニュアルページ:

ファイル記述子が同じプロセス内の他のスレッドのシステム コールによって使用されている可能性があるときに、ファイル記述子を閉じることはおそらく賢明ではありません。ファイル記述子は再利用される可能性があるため、意図しない副作用を引き起こす可能性があるいくつかの不明瞭な競合状態があります。

Linux を使用しているため、次の操作を実行できます。

  • を設定しeventfdて投票に追加する
  • eventfdfdを閉じたいときに信号を送る(それに書き込む)
  • 投票でアクティビティが表示されeventfdたら、すぐに fd を閉じてから削除できます。poll

または、単にsignalハンドラーを確立して、errno == EINTRいつpoll戻るかを確認することもできます。シグナルハンドラーは、グローバル変数を閉じているfdの値に設定するだけで済みます。


Linux を使用しているepollため、標準ではありませんが、優れた代替手段として検討することをお勧めしますpoll

于 2012-05-12T06:48:17.253 に答える