イベントがトリガーされると、スレッドプールのスレッドが使用されます。したがって、戻るよりも速くトリガーするイベントがたくさんある場合は、スレッドプールを使い果たします。したがって、スレッドが入る速度を制限する他のコントロールがなく、すぐに戻る保証がないイベントハンドラーメソッドがあり、その中に100%スレッドセーフなコードを丹念に実装していない場合はいつでもメソッドでは、スレッド制御を実装するのがおそらく最善です。明らかに簡単なことは、イベント処理メソッド内でlock()を実行することですが、これを行うと、最初のスレッドの後のすべてのスレッドがキューでブロックされ、ロック領域に入るのを待って、スレッドプールからすべてのスレッドを占有します。このメソッド内に別のスレッドがあることを検出し、代わりにすぐに中止する方がおそらく良いでしょう。
問題は、すでに実行されている別のスレッドを検出し、後続のスレッドをすばやく中止する方法があるということです。ただし、「const」を使用し、低レベルでロックフラグを手動で処理するため、C#っぽくはありません。もっと良い方法はありますか?
これは基本的にlock()機能の直接複製ですが、ブロッキングMonitor.Enter()を使用する代わりに、非ブロッキングInterlocked.Exchangeを使用します。
public class FooGoo
{
private const int LOCKED = 0; // could use any arbitrary value; I choose 0
private const int UNLOCKED = LOCKED + 1; // any arbitrary value, != LOCKED
private static int _myLock = UNLOCKED;
void myEventHandler()
{
int previousValue = Interlocked.Exchange(ref _myLock, LOCKED);
if ( previousValue == UNLOCKED )
{
try
{
// some handling code, which may or may not return quickly
// maybe not threadsafe
}
finally
{
_myLock = UNLOCKED;
}
}
else
{
// another thread is executing right now. So I will abort.
//
// optional and environment-specific, maybe you want to
// queue some event information or set a flag or something,
// so you remember later that this thread aborted
}
}
}