私が正しく理解していれば、必ずしも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
インターフェイスは異なりますが、考え方は同じです。
このテクニックは、セルフパイプ トリックとして知られています。