待ち合わせを行うオブジェクトのデストラクタ

WindowsAPIの同期オブジェクトにイベントというものがある。イベントは主に、複数のスレッド間での制御の同期に使用するものである。
たとえば、AスレッドとBスレッドという2つのスレッドがあり、この2つのスレッド間での制御の同期を考える。Aスレッドは処理の途中でBスレッドの処理の結果を必要とし、Bスレッドの処理が終わるまで、処理を一時停止する。Bスレッドは、処理を終了したら、そのことをAスレッドに通知し、Aスレッドの処理を再開させる。このBスレッドの処理の終了をAスレッドに通知するのにイベントを使用するのである。
このイベントという概念を使用することで、Producer-Consumerパターンといった、2つのスレッド間でのデータフローを実現することができるのだが、ここで一つ大きな問題がある。それは、あるスレッドが待ち合わせをしている最中に、条件となるイベントを破棄しようとした場合の処理である。WindowsAPIでは、スレッドが待ち合わせをしているのに、条件となるイベントを破棄してしまうと、そのスレッドは永久に再開されなくなってしまう可能性があるようだ(実験の結果)。
よって、イベントを破棄する前には必ず、待ち合わせをしているスレッドを全て再開させてやる必要がある。しかし、ここにも大きな落とし穴がある。たとえば、Producer-Consumerパターンで、Channel役のオブジェクトにイベントをフィールドとして持たせたとする。Producer役のスレッドとConsuer役のスレッドはChannel役のオブジェクトで待ち合わせを行うのだが、どちらか待ち合わせをしている最中にそのChannel役のオブジェクトのデストラクタを呼び出した場合、破棄する前にイベントをリセットして待ち合わせをしていたスレッドを再開させてしまうと、再開されたスレッドが破棄されたリソースにアクセスしてエラーを起こしてしまう可能性がある。
破棄されたリソースへのアクセスを回避するためには、再開されたスレッドのリソースへのアクセスの終了を全て終わったのを確認してから、リソースの解放を行う必要がある。こうすることで正常にオブジェクトの破棄をすることができると思われる。
が、ここまで考えてもまだ、問題は残る。それは、再開したスレッドがリソースへのアクセスの終了を待つ間に、新たにリソースへのアクセスを要求してくる可能性があるのだ。それを回避するには、破棄処理を開始したら、新規のアクセスを全て拒否するようにする必要がある。
と、この3連休は、この問題をずーと考えていました。しかし、未だにこの考えを実現した実装が思いつかない…。