从多个线程同时向全局变量添加值?

时间:2011-10-14 18:53:52

标签: c# .net multithreading

如何同时为变量添加值?如果我可以得到什么结果?崩溃或其他什么?
例如:

int a;


所以将有2个线程一次添加值。
感谢

4 个答案:

答案 0 :(得分:4)

未定义2个线程添加到共享值而没有任何同步的行为。写不会导致任何崩溃。它只会将值保留为其中一个线程所见的最终值

为了获得定义的行为,您需要添加某种同步,例如锁定。

internal static class Holder {
  static object m_lock = new object();
  static int a;
  internal static void Add(int value) {
    lock (m_lock) {
      a += value;
    }
  }
}

答案 1 :(得分:3)

如果以不受控制的方式执行此操作,很可能会丢失数据。

每个主题将采取三个步骤:

  • 读取值
  • 增加副本
  • 存储增加的值

如果它们大致同时执行第一步,则结果将是1而不是2的增量。

此外,存在内存模型问题,其中一个线程可能无法“看到”来自另一个线程的写入。记忆模型是复杂的野兽......

使用Interlocked.Increment执行原子增量,该增量还使用易失性内存访问来确保它始终可以看到其他线程所写的内容。

破损代码示例:

using System;
using System.Threading;

class Test
{
    const int Iterations = 1000000;

    static int counter;


    static void Main()
    {
        Thread t1 = new Thread(AddLots);
        t1.Start();
        AddLots();
        t1.Join();
        Console.WriteLine(counter);
    }

    static void AddLots()
    {
        for (int i = 0; i < Iterations; i++)
        {
            // Broken!
            counter++;
        }
    }
}

刚才在笔记本电脑上运行,结果显示为1011788。

更改此行:

counter++;

到此:

Interlocked.Increment(ref counter);

这一切都很美妙。

答案 2 :(得分:2)

这是不可能的 - 从两个线程同时写入相同的内存地址。这将是race condition并非崩溃。您可以使用锁定技术(请参阅lock statement)或其他同步机制。另外我要注意.NET Framework提供了一组方法(参见Interlocked class),它们保证操作是原子的,有Add,Increment,Decrement,Exchange,CompareExchange。

答案 3 :(得分:0)

如果您为两个线程中的变量赋值,那么如果您不使用线程同步技术保护变量,那么变量将具有什么值是不可预测的。如果要确保添加这两个值,则需要确保一次只能执行一个有问题的代码。