コードのブロックを排他的に実行する必要があるメソッドがありますが、本当に必要な場合にのみこの制限を追加したいと考えています。Id 値 (Int32) によっては、個別のオブジェクトをロード/変更することになるため、すべてのスレッドのアクセスをロックしても意味がありません。これを行う最初の試みは次のとおりです-
private static readonly ConcurrentDictionary<int, Object> LockObjects = new ConcurrentDictionary<int, Object>();
void Method(int Id)
{
lock(LockObjects.GetOrAdd(Id,new Object())
{
//Do the long running task here - db fetches, changes etc
Object Ref;
LockObjects.TryRemove(Id,out Ref);
}
}
これが機能するかどうかは疑問です-TryRemoveが失敗する可能性があります(これにより、ConcurrentDictionaryが大きくなり続けます)。
より明白なバグは、TryRemove がオブジェクトを正常に削除することですが、このオブジェクトを待機している (ロックアウトされている) (同じ ID の) 他のスレッドがある場合、同じ ID を持つ新しいスレッドが入ってきて、新しいオブジェクトを追加することです。追加したばかりのオブジェクトを待っている人が他にいないため、オブジェクトが処理を開始します。
代わりに、TPL またはある種の ConcurrentQueue を使用してタスクをキューに入れる必要がありますか? 最も簡単な解決策は何ですか?