1つのユニークな項目だけを同時に処理できるようにするには、同期メカニズムが必要です。そこで、Monitor.Enterを使用して、同じアイテムの他の同時実行をブロックしました。Monitor.Enterは他のタスクをブロックしません
ここでは、論理を検証するための私のコードとユニットテストのカットバージョンです。
私のコレクションのいくつかのアイテムは、Monitorからロックを取得できることがわかります。アイテムが取得されたときにロックを解除しないため、複数のアイテムが発生してはいけません。
なぜ私は通貨のコレクションのアイテムのいくつかが価値が2か3を持っているのを見ますか?私が持っている2時には3値として通貨コレクション内の項目のいくつかを見るのはなぜ
[TestClass]
public class UnitTest2
{
public static ConcurrentDictionary<string, object> _keyLocks =
new ConcurrentDictionary<string, object>();
public static object AcquireLock(string item)
{
object obj = _keyLocks.GetOrAdd(item, new object());
Monitor.Enter(obj);
}
[TestMethod]
public void AcquireLock_MultipleRequest_OnlyAllow1Request()
{
Dictionary<string, int> currencies = new Dictionary<string, int>() {
{ "USD",0 },
{ "EUR",0 },
{ "TRY",0 },
{ "AUD",0 },
{ "PLN",0 }
};
int totalTask = 1000;
List<Task> tasks = new List<Task>();
for (int i = 0; i < totalTask; i++)
{
string curr = currencies.Keys.ElementAt(i % currencies.Count);
tasks.Add(Task.Factory.StartNew((obj) =>
{
string currStr = (string)obj;
AcquireLock(currStr);
currencies[currStr] += 1;
//Monitor.Exit will be implemented
}, curr));
}
Thread.Sleep(10000);
foreach (var item in currencies.Keys)
{
Assert.AreEqual(1, currencies[item]);
}
}
}
'ConcurrentDictionary'に追加するためのロックは必要ありません。' GetOrAdd() 'を使用してください。 – xxbbcc
コメントをいただきありがとうございます。最初にGetOrAddを使用しましたが、thlsの後に問題が発生していると思われます。なぜなら、オーバーロードされたバージョンのValueOptをスレッドセーフではなく複数回呼び出すことができるからです。同じキーの新しいオブジェクト。 – Yucel
バリューファクトリーの使い方を知っていればバリューファクトリーには何も問題はありません。特にあなたのケースでは、それはちょうど 'new object()'なので、複数回呼び出されても、実際には1つのオブジェクトだけがマップに配置されます。現在のコードよりもはるかに効率的です。 – xxbbcc