为什么以下 C# 多线程代码在调试器中输出零但不输出零?
class Program
{
private static volatile int value;
public static void Increment()
{
for (int i =0; i <100000; i++)
{
value++;
}
}
public static void Decrement()
{
for (int j =0 ; j < 100000; j++)
{
value--;
}
}
public static void ThreadTest()
{
value = 0;
var incrementThread = new Thread(Increment);
var decrementThread = new Thread(Decrement);
incrementThread.Start();
decrementThread.Start();
incrementThread.Join();
decrementThread.Join();
Console.WriteLine("Value of value {0}", value);
}
static void Main(string[] args)
{
ThreadTest();
}
}
class Program
{
private static volatile int value;
public static void Increment()
{
for (int i =0; i <100000; i++)
{
value++;
}
}
public static void Decrement()
{
for (int j =0 ; j < 100000; j++)
{
value--;
}
}
public static void ThreadTest()
{
value = 0;
var incrementThread = new Thread(Increment);
var decrementThread = new Thread(Decrement);
incrementThread.Start();
decrementThread.Start();
incrementThread.Join();
decrementThread.Join();
Console.WriteLine("Value of value {0}", value);
}
static void Main(string[] args)
{
ThreadTest();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为它不应该... ++ 和 -- 不是原子操作(与 Interlocked.XXXX 操作 - Interlocked.Increment 不同)。
如果你写下 ++ 和 -- 的每个步骤,看看两者如何被不同的线程混合,你就会明白为什么:
递增
递减
因此,如果顺序是 1,2,3,4,5,6,你会得到 value = 0 ;但如果顺序是 1,2,4,5,6,3,则值 = 1。
Because it is not supposed to... ++ and -- are not atomic operations (unlike Interlocked.XXXX opreations - Interlocked.Increment).
If you write down each step of ++ and -- and see how both can be intermixed by different threads you'll see why:
increment
decrement
So if order is 1,2,3,4,5,6 you get value = 0; but if order is 1,2,4,5,6,3 you get value = 1.
只是想让事情变得更简单......我当天也解决了这个问题:D
Volatile 确保您读取最新值,并且当您写入所有线程时看到新值(这就是易失性操作的用途) ,但它不能确保在读取和写入之间,其他线程不会修改该值。另一方面,Interlocked(提供原子操作)确实确保了这一点。
例如,当一个或多个线程读取和其他修改时,易失性操作是好的。例如,如果您的类中有一个
易失性布尔_dispose
标志,那么如果一个线程处置它,它会立即被标记为所有线程的处置。Only trying to make the things simpler... I fought this issue back in the day as well :D
Volatile ensure you read the latest value, and when you write all threads see that new value (and that is what volatile operations are for), but it doesn't ensure that between the read and the write, other thread is not going to modify the value. In the other hand, Interlocked (that provides atomic operations) does ensure it.
Volatile operations are good, when for example a thread or threads read and other modify. For example if you have a
volatile Boolean _disposed
flag in your class, so if one thread dispose it, it's marked as disposed for all threads straight away.