2个线程增加一个静态整数

4
如果我同时使用两个不同的任务或线程来增加一个静态变量,我需要锁定它吗?
我有一个类将被多个线程同时使用,它返回一个代理以在线程内部使用,但我不希望每个线程同时使用相同的代理,所以我认为递增一个静态整数是最好的方法,您有什么建议吗?
class ProxyManager
{
    //static variabl gets increased every Time GetProxy() gets called
    private static int Selectionindex;
    //list of proxies
    public static readonly string[] proxies = {};
    //returns a web proxy
    public static WebProxy GetProxy()
    {
      Selectionindex = Selectionindex < proxies.Count()?Selectionindex++:0;
      return new WebProxy(proxies[Selectionindex]) { Credentials = new NetworkCredential("xxx", "xxx") };
    }
}

基于所选答案

if(Interlocked.Read(ref Selectionindex) < proxies.Count())
{
    Interlocked.Increment(ref Selectionindex);
}
else
{
    Interlocked.Exchange(ref Selectionindex, 0);
}

Selectionindex = Interlocked.Read(ref Selectionindex);

1
如果我在两个不同的任务或线程中增加一个静态变量,我需要对其进行锁定吗?只有这样才能得到正确的答案。 - Pieter Geerkens
1个回答

6

如果在多个线程中增加一个静态变量,结果会不一致。取而代之的是使用Interlocked.Increment

private void IncrementSelectionIndex() {
    Interlocked.Increment(ref Selectionindex);
}

64位的读取是原子的,但为了完全支持32位系统,您应该使用Interlocked.Read

private void RetrieveSelectionIndex() {
    Interlocked.Read(ref Selectionindex);
}

1
应该使用Interlocked.Add将变量设置回0:Interlock.Add(SelectionIndex, -SelectionIndex); - Guillaume
2
如果你使用-SelectionIndex,你必须使用Interlocked.Read来确保在32位系统上安全,即使这样...除非你将Interlocked.Add放在锁定任意object的锁定块内,否则仍可能会创建问题。因此,是的,使用Interlocked.Exchange(ref Selectionindex, 0) - cfeduke
@cfeduke,请检查一下我在问题中更新的代码,是否没问题? - user1590636
1
看起来需要将Selectionindex的使用封装到自己的类中(单例或静态),命名为AtomicCount,并提供像GetInterlocked.Read)、ResetInterlocked.Exchange)和bool IsLessThan(Int32)这样的方法来替换if条件测试。我会出于可维护性和可读性的考虑这样做。 - cfeduke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接