======关于多线程的一个示例,困惑,盼高手解惑=======

愚者只看星不看答案 2012-02-10 09:05:39
如果线程之间有共同的引用,则它们共享数据。例如下面代码::

1: class ThreadTest
2: {
3: bool done;
4:
5: static void Main()
6: {
7: ThreadTest tt = new ThreadTest(); // Create a common instance
8: new Thread(tt.Go).Start();
9: tt.Go();
10: }
11:
12: // Note that Go is now an instance method
13: void Go()
14: {
15: if (!done) { done = true; Console.WriteLine("Done"); }
16: }
17: }
18:
19:

因调用Go()方法的两个线程,拥有同一个引用,所以结果打印出来的是一个 ”Done”而不是两个。

上面都是那个示例的原话。

但是我的理解下:
假设那个实例化的线程执行到GO方法中的if(!done)后,该线程的时间片已到或调度程序把该线程挂起。主线程此时执行,并且完整的执行了整个方法。因为刚才那个实例化的线程还未来得及修改done的值为true,此时该实例化的线程再次被调度,此时,从挂起的地方if(!done){ 这里开始执行(因为已经在挂起前已经做过了判断),依然会执行后面的done=true.....,也就是说完全存在Done被输出两次的可能性。

我的说法正确吗?请指教。
...全文
1730 41 打赏 收藏 转发到动态 举报
写回复
用AI写文章
41 条回复
切换为时间正序
请发表友善的回复…
发表回复
蔡袅 2012-02-17
  • 打赏
  • 举报
回复
因为无同步机制;
在多核CPU的情况下,应该很容易会出现打印两次done。
蔡袅 2012-02-17
  • 打赏
  • 举报
回复
其实done并未初始化无法编译通过,
如果初始化为false那么
我觉得可能输出两个,也可能只输出一个;
ThreadTest tt = new ThreadTest();
new Thread(tt.Go).Start();//工作线程调用tt.Go
tt.Go();//主线程调用tt.Go

因为两者是共用同一个判断变量done,而且又无同步机制,
如果其中一个线程(主线程或工作线程随意)先进入if语句之内,还没执行done=true而另一个线程也进入
那么这时候修改就毫无意义,会打印两次,否则一个进入if之后执行了判断另一个线程才进入则只会执行一次。
s8110208 2012-02-17
  • 打赏
  • 举报
回复
据我估计 应该是你的两个线程中的一个 已经把bool done这样一个值改变了 然后另一个线程 自然是不能调用到Go() 这样一个函数 就只有一行输出
biacyan 2012-02-17
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 sp1234 的回复:]
真的,要知道做一个程序员,你不是什么“三重门的粉丝”,而是一个软件设计师。所以从逻辑出发,就算打官司也不是为了噱头,而是真的是就是一种学术怀疑而已(但是学术争论可以打上官司也够可以的了)。
[/Quote]

我只是简单的来鄙视这个人的语气的
startstartsvip 2012-02-15
  • 打赏
  • 举报
回复
这么基础的东西,咋弄那么多人来讨论,都是吐草来的吗?
b87936260 2012-02-14
  • 打赏
  • 举报
回复
把done synchronized起来不行吗?
吹风的兔子 2012-02-14
  • 打赏
  • 举报
回复
 1:  class ThreadTest
2: {
3: bool done;
4:
5: static void Main()
6: {
7: ThreadTest tt = new ThreadTest(); // Create a common instance
8: new Thread(tt.Go).Start();
9: tt.Go();
10: }
11:
12: // Note that Go is now an instance method
13: void Go()
14: {
15: if (!done)
{
Thread.Sleep(3000); //线程近来休眠 3秒;
done = true;
Console.WriteLine("Done");
}
16: }
17: }


这时,理论上将 就会 打印两次 “Done”;
线程之间的切换 也是如此,谁也不能确保线程会执行到 哪一步的时候被切换,
就像在 执行到 Thread.Sleep(3000); 地方被休眠一样;


因此,楼主的猜想是正确的!!!!
——一般情况下,因为线程正好在 Thread.Sleep(3000); 这个点 进行切换的概率太低,所以给人造成一种只执行一次的错觉;


确实有可能执行两次!!!
cc_MineMine 2012-02-13
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 truelove12 的回复:]

to:caozhy

哥们,您就说吧,根据您自己的理解,您认为done输出两次的可能有没有吧。
[/Quote]

我觉得没有这种可能 一定是多线程先调用他 当然这个是不考虑外界因素的情况下
dustindwind 2012-02-12
  • 打赏
  • 举报
回复
AutoResetEvent需要user-mode到kernel-mode的转换,所以从效率上考虑,不如使用纯user-mode的同步机制。《CLR via C#》书中给出一个实例,效率大概相差80倍。当然,因为同步事件在实际中往往不经常发生,所以一般不会成为性能瓶颈所在... But still it's good to be aware of this, just in case.
zmkkobe 2012-02-12
  • 打赏
  • 举报
回复
也学习学习
nonocast 2012-02-12
  • 打赏
  • 举报
回复
我一般直接用AutoResetEvent来控制线程切换,其他我都不放心。。。汗
还有现在Intel CPU优化以后你根本搞不清,你以为会截断的地方,从asm的角度去看,其实直接就被优化掉了,这种东西到我们这个层面直接无视
Yujiexiaoyu 2012-02-11
  • 打赏
  • 举报
回复
稍微改一下。验证看会不会出现两次。
sugarbelle 2012-02-11
  • 打赏
  • 举报
回复
太高深..
我连done什么时候赋值是false都不知道.
  • 打赏
  • 举报
回复
真的,要知道做一个程序员,你不是什么“三重门的粉丝”,而是一个软件设计师。所以从逻辑出发,就算打官司也不是为了噱头,而是真的是就是一种学术怀疑而已(但是学术争论可以打上官司也够可以的了)。
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 truelove12 的回复:]

to:sp1234

您来得实际的。。。。说说您的看法。

您说:
任何两条语句之间,变量都可能被改变。

那么请问一条语句就不会改变吗?
i+=1;
这是一条语句,但是在c#中也不是原子的。
如果被多线程访问,也有可能出现意料之外的结果。

所以您说的是不成立的。
[/Quote]

晕!你这个就是抬杠,看来你一点也没有逻辑只是,以前大概语文也是从来都拿20分吧。

“任何两条语句之间,变量的值都可能改变”,这跟你说“甚至一条语句,变量得知都可能改变”矛盾么?对于你的这个强加的所谓“矛盾”概念,我真的觉得毫无逻辑可言。所以我只能说你太心急了,太想一下在就愤青成功了。

先要耐心一点,提高自身逻辑推理理解。
  • 打赏
  • 举报
回复
感谢 所有回复的朋友,我先看看。。
  • 打赏
  • 举报
回复
感谢参与回复的所有朋友,我先看看。。
苦苦的潜行者 2012-02-11
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 sugarbelle 的回复:]

太高深..
我连done什么时候赋值是false都不知道.
[/Quote]

难道不是构造器赋值false吗?


我是了n编,结果永远是打印了第一个线程的Done,而
Go(b);这儿就不会打印.
using System;
using System.Threading;
class Test
{
static bool done = true;
static readonly object locker = new object();
static Test()
{
Console.WriteLine(done.ToString());
done = false;
Console.WriteLine(done.ToString());
}
static void Main()
{
Param i = new Param();
i.I = 0;
Thread aa = new Thread(new ParameterizedThreadStart(Test.Go));
aa.Start(i);
Param b = new Param();
b.I = 0;
Go(b);
Console.ReadKey();
}

static void Go(object i)
{
Param a=(Param)i;
a.I++;
lock (locker)
{
if (!done) { Console.WriteLine("{0}", a.I + " Done"); done = true; }
}
}
}
class Param {
private int i;
public int I{
get { return i; }
set { i = value; }
}
}
threenewbee 2012-02-11
  • 打赏
  • 举报
回复
多线程编程的难度是比较大的,必须从源代码的角度去分析有没有问题,而不能依赖黑盒测试。一些问题出现的概率极低,另一些甚至只对某个特定的环境才出问题。

即便是微软的产品,也出现过问题。当年微软的 IE6,在单 CPU 和多 CPU 上都运行无误,但是在超线程的 CPU 上就会出现死锁。

文章作者的意图也是如此,让你认识到多线程运行的不确定性。但是如果你没有阅读完,那就麻烦了,如果理解成概率低,运行的时候遇不到就是正确的,那就反掉了。
猴头 2012-02-11
  • 打赏
  • 举报
回复
恩 我说错了。。。。
加载更多回复(18)

110,500

社区成员

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

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

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