5

この関数を含む C++ アプリケーションがあります。

int
mySelect(const int fdMaxPlus1,
         fd_set *readFDset,
         fd_set *writeFDset,
         struct timeval *timeout)
{
 retry:
  const int selectReturn
    = ::select(fdMaxPlus1, readFDset, writeFDset, NULL, timeout);

  if (selectReturn < 0 && EINTR == errno) {
    // Interrupted system call, such as for profiling signal, try again.
    goto retry;
  }

  return selectReturn;
}

select()通常、このコードは問題なく動作しますが、あるインスタンスで、コードで失敗し続ける無限ループに陥るのを見ましたEINTR errno。この場合、呼び出し元はタイムアウトを 0 秒と 0 マイクロ秒に設定しました。つまり、待機せずselect()にすぐに結果を返します。シグナルハンドラーが発生したときにのみ発生すると思っていEINTRましたが、シグナルハンドラーを何度も (12 時間以上) 取得し続けるのはなぜですか? これは Centos 5 です。これをデバッガーに入れて何が起こっているかを確認すると、数回の反復の後、コードは EINTR なしで返されました。チェックされる fd はソケットであることに注意してください。

上記のコードに再試行制限を追加することもできますが、まず何が起こっているのかを理解したいと思います。

4

1 に答える 1

1

Linux では、select(2)はタイムアウト引数 (アドレスで渡される)を変更する場合があります。そのため、呼び出し後にコピーする必要があります。

retry:
struct timeout timeoutcopy = timeout;
const int selectReturn
  = ::select(fdMaxPlus1, readFDset, writeFDset, NULL, &timeoutcopy);

(あなたのコードでtimeoutは、数回または最初の反復の後、おそらくゼロまたは非常に小さいです)

ところで、代わりにpoll(2)selectを使用することをお勧めします( pollC10K の問題に適しているため)

ところで、登録されたシグナルハンドラーがなくても、EINTR任意のシグナルで発生します(signal(7)を参照)。

straceプログラムの全体的な動作を理解するために使用できます。

于 2015-02-11T20:00:57.010 に答える