2

重複の可能性:
ウェイクアップ スレッドが accept() 呼び出しでブロックされる

カスタム停止信号が送信されるまで、接続をリッスンする (接続を受け入れてワーカー スレッドに渡す) 小さなサーバーを作成しています。

ブロッキング ソケットを使用すると、カスタム停止シグナルが送信されたときに、メインの受け入れループを中断できません。ただし、ノンブロッキング ソケットでのビジー ウェイト/スピンロック ループは避けたいと考えています。

私が望むのは、接続が受信されるか停止信号が送信されるまで、メインの受け入れループがブロックされることです。

これは Linux の C で可能ですか?

どうもありがとう。

4

2 に答える 2

2

私が正しく理解していれば、必ずしもPOSIXシグナルではなく、あらゆる種類の「シグナル」を使用することにオープンです。実際には、POSIX シグナルをループで受信したかどうかを確認すると競合状態が避けられないため、POSIX シグナルは適切な選択ではありません。

使用する必要があるのは、ファイル記述子を介して監視できるものです。かもしれない:

  • パイプ。受け入れループは、パイプの読み取り側を監視します。ループを起こすために、別のスレッドが何かを (何であっても構いません) 書き込み側に書き込みます。
  • 別のソケット。同様に、別のスレッドがソケットのもう一方の端に書き込むことで、受け入れループを起こします。
  • inotify を使用して監視するファイルシステム内のファイル。
  • ループを中断する必要があるときにデータを受信するデバイス。
  • 等...

例のリストの後半のエントリは、一般的に実用的ではありません。これらは、監視可能なファイル記述子を持っている限り、オブジェクトのタイプを問わないことを示すためのものです。最も簡単で、安価で、最も人気のある方法はパイプです。

すでにノンブロッキング ソケットを使用している場合は、接続を受け入れる準備ができているかどうかを確認するための何らかのポーリング ループが既に存在します。これを行うために使用していると仮定しますpoll()

ループを開始する前に、次のようにパイプを設定します。

pipe(&pipefd[0]);
read_end = pipefd[0];
write_end = pipefd[1];
fcntl(read_end, F_SETFL, O_NONBLOCK);

これfcntlは、パイプの読み取り側を非ブロッキング モードに設定することです。pollソケットと一緒に呼び出しでパイプのその端を使用するため、ノンブロッキングである必要があります。

次に、受け入れループで監視するタイル記述子のリストに、パイプの読み取り側を追加します。

for (;;) { /* accept loop, loop forever */
    /* Monitor your socket. You should already have this in your code */
    pollfd[0].fd = your_socket;
    pollfd[1].events = POLLIN;

    /* Add a new entry to monitor the read end of the pipe */
    pollfd[1].fd = read_end;
    pollfd[1].events = POLLIN;

    /* Now call poll, as before, but monitor 2 file descriptors instead of just 1 */
    n = poll(&pollfd[0], 2, -1);

    /* Check if your socket is ready to accept.
       This part, you are already doing. */
    if (pollfd[0].revents) {
        newsocket = accept(your_socket, etc....)
        do_somehting_with(new_socket);
    }

    /* New part: check if anyone has written something for you into your pipe */
    if (pollfd[1].revents) {
        break; /* stop the loop */
    }
}

例では使用してpollいますが、代わりにselect(またはepoll) を使用している可能性があります。selectインターフェイスは異なりますが、考え方は同じです。

このテクニックは、セルフパイプ トリックとして知られています。

于 2012-11-10T16:18:41.737 に答える
0

ブロッキング解除ソケットを accpet() に渡したくない場合は、シグナルを送信します (説明のとおりman signalaccept()ing スレッドにシグナルを送信することが、ブロッキングaccept()(接続の待機) を中断する唯一の方法です)。

一部のコメンターによってすでに指摘されているように、ほとんどのシステム コール (を含むaccept()) は、スレッドがシグナルを受信すると中断されます。

accept()戻り-1、シグナルによって中断された呼び出しにerrno設定されている場合。EINTRaccept()

プロセスにシグナルを送信するには、 を使用しますkill(<pid>, <signal-number>)

マルチスレッド環境にいる場合は、他のすべてのスレッドで使用するシグナル (通常SIGUSR1または) をブロックしますが、プロセスに送信されたシグナルをプロセスのどのスレッドが処理するかは非決定論的であるため、SIGUSR2を呼び出すスレッドはaccept()(プロセスを介して「対処」されますpid。)

pthread_kill(<pthread>, <signal-number>)または、特定のスレッドのみにシグナルを送信するために使用できます。

于 2012-11-10T16:02:19.667 に答える