我有一个只增加整数值(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;
}
答案 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不受编译器的限制 假设访问的优化 单线程。这确保了 最新的价值存在于 在任何时候都在这个领域。