以下のコードでは、KernalRecursiveAutoResetEventという同期制御に使用されるクラスがあります。これには、ロックのためのAutoResetEvent WaitOne()と解放のためのSet()を呼び出すLock and Leaveメソッドがあります。ループをセットアップして、共有リソースを扱うメソッドを呼び出すことができます。メソッドIncrementでは、intを共有リストに追加します。 LeaveはLockよりも速く呼び出されているため、競争相手はfalingです。実行を制御するより良い方法はありますか?現在のスレッドが所有スレッドと等しいかどうかをチェックする条件は、所有スレッドがLock()メソッドで設定される直前に実行されるため、InvalidOperation例外がスローされます。再帰的自動修復での競合状態の解決
ヒント?
class KernalRecursiveAutoResetEvent : IDisposable
{
private AutoResetEvent m_lock = new AutoResetEvent(false);
private int m_owningThreadId = 0;
private int m_recusionCount = 0;
public void Lock()
{
int currentThreadId = Thread.CurrentThread.ManagedThreadId;
if (m_owningThreadId == currentThreadId)
{
m_recusionCount++;
return;
}
m_lock.WaitOne();
m_owningThreadId = currentThreadId;
m_recusionCount = 1;
}
public void Leave()
{
if (m_owningThreadId != Thread.CurrentThread.ManagedThreadId)
throw new InvalidOperationException();
if (--m_recusionCount == 0)
{
m_owningThreadId = 0;
m_lock.Set();
}
}
public void Dispose()
{
m_lock.Close();
}
}
using (var rare = new KernalRecursiveAutoResetEvent())
{
for (int i = 0; i < iterations; i++)
{
var t = new Thread(a => Increment(ref i, rare));
t.Start();
rare.Lock();
}
}
private static void Increment(ref int i, object _lock)
{
Increment(ref i);
if (_lock is KernalRecursiveAutoResetEvent)
{
var m_lock = _lock as KernalRecursiveAutoResetEvent;
m_lock.Leave();
}
else if (_lock is KernalModeMutexSimpleWaitLock)
{
var m_lock = _lock as KernalModeMutexSimpleWaitLock;
m_lock.Leave();
}
else if (_lock is KernalModeSemaphoreSimpleWaitLock)
{
var m_lock = _lock as KernalModeSemaphoreSimpleWaitLock;
m_lock.Leave();
}
else if (_lock is KernalModeSimpleWaitLock)
{
var m_lock = _lock as KernalModeSimpleWaitLock;
m_lock.Leave();
}
}
private static void Increment(ref int i)
{
i++;
}
"LeaveはLockより速く呼び出されています" - なぜLeaveを呼び出すコードを投稿しないのですか?同期プリミティブを従来のもの(つまり、説明されている正確な機能を持つ 'Monitor')で置き換えることもできますが、コードが' Enter'の前に 'Exit'を呼び出すと問題は残るでしょう。 –
leaveを呼び出すコードは単純ですが、Iをインクリメントし、rare.Leave()を呼び出します(AutoResetEvent.Set()を呼び出します) 問題はMonitor.EnterまたはExit/TryExitを理解していません。それを制御する.FCL静的なMonitor.EnterとLeave/TryLeaveなどのいくつかの根本的な問題があります。これは、ロックしていない理由、競合状態の制御に失敗したためロックしていない理由を理解することではありません。どのようにLeaveが呼び出される前にLock –