Bul*_*nes 5 c# multithreading .net-4.0
从这个线程跳出来,我正在尝试使用ConcurrentDictionary来复制以下内容:
public static class Tracker
{
private static Dictionary<string, int> foo = new Dictionary<string, int>();
private static object myLock = new object();
public static void Add(string bar)
{
lock(myLock)
{
if (!foo.ContainsKey(bar))
foo.Add(bar, 0);
foo[bar] = foo[bar] + 1;
}
}
public static void Remove(string bar)
{
lock(myLock)
{
if (foo.ContainsKey(bar))
{
if (foo[bar] > 0)
foo[bar] = foo[bar] - 1;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我最初的尝试是:
public static class Tracker2
{
private static ConcurrentDictionary<string, int> foo =
new ConcurrentDictionary<string, int>();
public static void Add(string bar)
{
foo.AddOrUpdate(bar, 1, (key, n) => n + 1);
}
public static void Remove(string bar)
{
// Adding a 0'd item may be ok if it wasn't there for some reason,
// but it's not identical to the above Remove() implementation.
foo.AddOrUpdate(bar, 0, (key, n) => (n > 0) ? n - 1 : 0);
}
}
Run Code Online (Sandbox Code Playgroud)
这是正确的用法吗?我会避免以下情况:
该Add方法并不等效:如果那里不存在任何内容,则原始方法将首先添加0at foo[bar],然后递增,总结果为1at foo[bar]。如果那里不存在,第二个将添加 a 0,并且仅在后续调用中执行增量。
该Remove方法并不等效:如果foo.ContainsKey(bar)is ,您的原始方法将不执行任何操作,而第二个方法将为该键false添加值。0
您阅读过 的文档吗AddOrUpdate?
编辑:在您编辑解决上述问题后,您的问题的答案更清楚“不,它不会解决您的问题。” 原因在于Remove方法:它的操作现在是非原子的,因为有两个单独的原子操作:TryGetValue和foo[bar] = currValue - 1。另一个线程可能会介入这些操作并导致您担心的不一致。
AddOrUpdate像or 这样的方法的要点GetOrAdd是使公共操作尽可能原子化。不幸的是,他们似乎没有将您的案例原子化ConcurrentDictionary;没有UpdateIfExists。
但是,我非常确定以下方法可以解决您的问题:方法Interlocked.Decrement。这解决了以下情况:
foo[bar]具有值2,该值被存储在 中currValue。Add在那里被调用;foo[bar]增加到3.foo[bar]为 value currValue - 1 = 1。我试图考虑其他可能会失败的案例,但不能......这可能只是意味着我不如其他反对的评论者,尽管:P。
编辑2:我想到了使用的一个问题Interlocked.Decrement:如果它的值为正,它不仅会递减:(。
| 归档时间: |
|
| 查看次数: |
2467 次 |
| 最近记录: |