派生型は、基本クラスの型引数として静的セマフォと共に使用され、各サブクラスのすべてのインスタンス間で共有される 1 つのセマフォを取得します。そして、アクティブなタイプが 1 つだけであることを確認するための混乱があります。簡単なテストでは、これが正しく機能することを示していますが、問題があります。
たとえば、 のメソッドClassA1
が現在実行中であるとします。このメソッドを実行するための新しいリクエストが頻繁に到着すると、 class のメソッドを実行する新しいスレッドが常に存在するため、他の派生クラスが実行される機会がなくなる可能性がありますClassA1
。
internal abstract class ClassA<TDerived> : ClassA
{
private const Int32 MaximumNumberConcurrentThreads = 3;
private static readonly Semaphore semaphore = new Semaphore(ClassA<TDerived>.MaximumNumberConcurrentThreads, ClassA<TDerived>.MaximumNumberConcurrentThreads);
internal void MethodA()
{
lock (ClassA.setCurrentlyExcutingTypeLock)
{
while (!((ClassA.currentlyExcutingType == null) || (ClassA.currentlyExcutingType == typeof(TDerived))))
{
Monitor.Wait(ClassA.setCurrentlyExcutingTypeLock);
}
if (ClassA.currentlyExcutingType == null)
{
ClassA.currentlyExcutingType = typeof(TDerived);
}
ClassA.numberCurrentlyPossiblyExecutingThreads++;
Monitor.PulseAll(ClassA.setCurrentlyExcutingTypeLock);
}
try
{
ClassA<TDerived>.semaphore.WaitOne();
this.MethodACore();
}
finally
{
ClassA<TDerived>.semaphore.Release();
}
lock (ClassA.setCurrentlyExcutingTypeLock)
{
ClassA.numberCurrentlyPossiblyExecutingThreads--;
if (ClassA.numberCurrentlyPossiblyExecutingThreads == 0)
{
ClassA.currentlyExcutingType = null;
Monitor.Pulse(ClassA.setCurrentlyExcutingTypeLock);
}
}
}
protected abstract void MethodACore();
}
で実際の実装を呼び出すには、ラッパー メソッドが使用されることに注意してくださいMethodACore
。すべての派生クラス間で共有されるすべての同期オブジェクトは、非ジェネリック基本クラスにあります。
internal abstract class ClassA
{
protected static Type currentlyExcutingType = null;
protected static readonly Object setCurrentlyExcutingTypeLock = new Object();
protected static Int32 numberCurrentlyPossiblyExecutingThreads = 0;
}
派生クラスは次のようになります。
internal sealed class ClassA1 : ClassA<ClassA1>
{
protected override void MethodACore()
{
// Do work here.
}
}
internal sealed class ClassA2 : ClassA<ClassA2>
{
protected override void MethodACore()
{
// Do work here.
}
}
残念ながら、これがどのように、そしてなぜ機能するのかを今すぐ説明する時間はありませんが、明日答えを更新します.