sleep() と WaitForSingleObject() と割り込み

既存の実装に:

while (condition) {
    sleep(2);
}

みたいな条件を満たしているかどうかを 2 秒間隔で確かめるコードがあったが、処理が最遅で 2 秒遅れるので、以下のように書き換えた。

WaitForSingleObject(hHandle, INFINITE);

条件が満たされた時点で ReleaseSemaphore(hHandle, 1, NULL); のように呼び出すことで、遅延が発生しなくなるようにした、というのが改修の内容。


このように改修したことで出た不具合がある。それは何か。


Ctrl+C が効かなくなったこと。


POSIX C の sleep は無条件で指定時間スレッドをブロックする。ただし、Ctrl+C などの割り込みがあった場合は制御を戻す。

一方の Win32 API の WaitForSingleObject はハンドルがシグナル状態になるか指定時間が経過するまでスレッドをブロックする。こちらは Ctrl+C で制御を返さない。

Ctrl+C で制御を返すようにするには、シグナルハンドラを実装して、その中でセマフォをリリースする必要がある。こんな感じになるだろう。

void handler(int signame) {
    if (signame == SIGINT) {
        ReleaseSemaphore(hHandler, 1, NULL);
        signal(SIGINT, handler);
    }
}

条件を満たすまで待つ部分も、割り込みを考慮して以下のようにしなければならない。

while (condition) {
    WaitForSingleObject(hHandle, INFINITE);
}


なお、この例は MinGW を使用して Windows 環境で Win32 APIPOSIX API を使用するという特殊な例で、通常は Win32 API だけ、または POSIX API だけを使用するのが望ましい。