关于增加和减少整数值的线程安全方式的困惑!!求高手解惑

liuzhenpolestar 2012-05-08 11:17:37
今天在MSDN的Interlocked.Increment 方法 (Int32) 的示例中看到两个变量经过“相同的”运算后,最后结果却不同,貌似理由是线程安全什么的 ,不太懂。现在把例子的代码贴出来了,请高手分析一下 为什么SafeInstanceCount和UnsafeInstanceCount两个变量的值不同??!! 我怎么感觉肯定相同呢!!唉 越来越发现自己编程学的好差!
例子如下:



下面的代码示例说明增加和减少整数值的线程安全方式。SafeInstanceCount 始终为 0。但是 UnsafeInstanceCount 不一定为 0,因为在增加和减少计数之间会出现争用条件。此效果在多处理器计算机上尤其明显。

using System;
using System.Threading;

class Test
{
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();

// Have the garbage collector run the finalizer for each
// instance of CountClass and wait for it to finish.
GC.Collect();
GC.WaitForPendingFinalizers();

Console.WriteLine("UnsafeInstanceCount: {0}" +
"\nSafeCountInstances: {1}",
CountClass.UnsafeInstanceCount.ToString(),
CountClass.SafeInstanceCount.ToString());
}

static void ThreadMethod()
{
CountClass cClass;

// Create 100,000 instances of CountClass.
for(int i = 0; i < 100000; i++)
{
cClass = new CountClass();
}
}
}

class CountClass
{
static int unsafeInstanceCount = 0;
static int safeInstanceCount = 0;

static public int UnsafeInstanceCount
{
get {return unsafeInstanceCount;}
}

static public int SafeInstanceCount
{
get {return safeInstanceCount;}
}

public CountClass()
{
unsafeInstanceCount++;
Interlocked.Increment(ref safeInstanceCount);
}

~CountClass()
{
unsafeInstanceCount--;
Interlocked.Decrement(ref safeInstanceCount);
}
}

...全文
82 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
事理 2012-05-08
  • 打赏
  • 举报
回复
整数前面加上virtual
liuzhenpolestar 2012-05-08
  • 打赏
  • 举报
回复
谢谢HttpResponse和wddw1986的精彩回答!!!!!!
谢谢!!!看了你们的指点 貌似我明白了些 呼呼~~
liuzhenpolestar 2012-05-08
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

整数前面加上virtual
[/Quote]
加上virtual干嘛?
  • 打赏
  • 举报
回复
首先你一定得知道这个概念,在c#中绝大多数的操作都不是原子的。
即使像简单的变量自增操作 a++,也不是原子的。
即这个 a++的操作有可能不是在一个时间片中执行完成的,执行a++的操作可能会被其它线程抢占。
而在此之间它没有预见到其它线程可能已经修改了a本身的值

Interlocked.Increment(ref safeInstanceCount)操作,或lock就是为了解决这个问题的。
让该操作原子完成,不被其它线程抢占。
  • 打赏
  • 举报
回复
首先你一定得知道这个概念,在c#中绝大多数的操作都不是原子的。
即使像简单的变量自增操作 a++,也不是原子的。
即这个 a++的操作有可能不是在一个时间片中执行完成的,执行a++的操作可能会被其它线程抢占。
而在此之间它没有预见到其它线程可能已经修改了a本身的值

Interlocked.Increment(ref safeInstanceCount)操作,或lock就是为了解决这个问题的。
让该操作原子完成,不被其它线程抢占。
cheng2005 2012-05-08
  • 打赏
  • 举报
回复
++操作其实是两个过程,
a++等同于
a = a+1;
这里面需要先把a的值取出来,然后加1,然后再把值赋给a
对于CPU来说这是两个过程,把a的值读出来,放到寄存器,累加,再把寄存器里的值读出来,赋值给a。
如果这个过程被打断会发生什么呢,以下的两个a++在不同线程中
a= 0;
a++;
a++;
第一个a++进行到给a赋值之前被打断,此时寄存器里的值是1。然后执行第二个a++。第二个a++执行之后a的值是1,然后切换回第一个给a赋值的阶段,相当于把之前算好的1赋值给a,所以两次a++之后a的值竟然是1.

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧