从线程增加Int时的竞争条件

时间:2011-07-07 07:27:30

标签: c# multithreading int

我有一个只增加整数值(i ++)的方法

public void Calculate()
{
for(int i=0;i<1500;i++)
 y++;
}

其中Y是Int类变量。

Thread thr1 = new Thread(Calculate);
thr1.Start();   
Thread thr2 = new Thread(Calculate);
thr2.Start();
Thread thr3 = new Thread(Calculate);
thr3.Start();
Thread thr4 = new Thread(Calculate);
thr4.Start();

通过使用Calculate Delegate启动4个线程,如果Y以值0开始,则Y值应为6000 但并不总是变成6000,有时我得到5993或6003所以有些情况下这个值不是逻辑应该的那个。 那么有什么解决方法可以防止这种情况,我不想在线程增加时阻塞Y,那么有没有办法从Multiply线程设置变量值并行?

编辑:它正在使用Interlock.Increment();,但它会降低算法的速度,因此正确且更快的做法是:

int i = 0;
int j = 0;
for (i = 0; i < 1500; i++)
{
j++;
this.label1.Text = y.ToString();
}
lock(y)
{
    y += j;
}

4 个答案:

答案 0 :(得分:9)

这是竞争条件。您需要使用Interlocked.Increment以线程安全的方式执行此操作。

答案 1 :(得分:2)

您遇到的不是精度损失,而是访问变量的线程不安全方式的结果。由于此变量在不同线程之间共享,因此您需要确保增量操作为原子。一旦线程A读取字段的值,您必须确保在线程A写回增量值之前,没有其他线程可以更改它

要阻止其他线程执行此操作,请使用Interlocked.Increment(ref Int32)静态方法以原子方式增加字段的值。

在这个特定的例子中,如果你的每个线程都有自己的私有字段来递增,那么可以在不锁定的情况下实现相同的结果(然后你可以在最后将它们全部加在一起)。您可以尝试发布您的实际代码,以便以类似的方式对其进行修改。

答案 2 :(得分:1)

您可以使用int值创建一个新对象y,这样您就可以在线程想要增加它时锁定对象y。这使得Calculate()线程安全。

            public void Calculate()
        {                
            for(int i = 0; i < 1500; i++)
            {
                lock (y)
                {
                    y.value++;
                }
            }
        }
  

lock关键字确保一个线程不进入代码的关键部分,而另一个线程处于临界区。如果另一个线程试图输入一个锁定的代码,它将等待,阻塞,直到该对象被释放。

http://msdn.microsoft.com/en-us/library/c5kehkcz%28v=VS.100%29.aspx

答案 3 :(得分:0)

我不是线程专家,所以我为这个答案穿上防火服,期待那些真正想要线索的人的抗议......但volatile关键字不会做OP想要的这个案子?

来自文档:

  

volatile关键字表示a   字段可能会被多个修改   正在执行的线程   时间。声明的字段   volatile不受编译器的限制   假设访问的优化   单线程。这确保了   最新的价值存在于   在任何时候都在这个领域。