首页 新闻 会员 周边 捐助

程序运行和调试的问题

0
[已解决问题] 解决于 2015-01-13 09:15

 List<UserModel> userList = new List<UserModel>
            {
                new UserModel{ UserName="jiejiep", UserAge = 26},
                new UserModel{ UserName="xiaoyi", UserAge = 25},
                new UserModel{ UserName="zhangzetian", UserAge=24}
            };
 public class TempClass
    {
        public UserModel um
        {
            get;
            set;
        }
 
        public void ShowMessage(object obj)
        {
            Thread.Sleep(1000);
            MessageBox.Show(um.UserName);
        }
    }
复制代码
复制代码
        TempClass tempCls = new TempClass();
        foreach (var u in userList)
        {
             tempCls.um = u;
 
             ThreadPool.QueueUserWorkItem((obj) =>
             {
                tempCls.ShowMessage(obj);
             });
        }

调试结果和运行结果不同,能不能给我解释一下

博学多思的主页 博学多思 | 初学一级 | 园豆:76
提问于:2015-01-12 13:52
< >
分享
最佳答案
0

不是调试和运行的区别,而是你这段代码本身就不是线程安全的。

也就是说语句  tempCls.um = u 和 MessageBox.Show(um.UserName) 并不是按照 foreach (var u in userList) 顺序来执行的,而是乱序执行。

奖励园豆:5
Launcher | 高人七级 |园豆:45050 | 2015-01-12 14:20

还是不太理解,能不能介绍的详细一点

调试的时候运行结果:jiejiep,xiaoyi,zhangzetian

运行记得结果:zhangzetian,zhangzetian,zhangzetian

我基础不太好!

博学多思 | 园豆:76 (初学一级) | 2015-01-12 14:23

@博学多思: 如果我说语句  ThreadPool.QueueUserWorkItem((obj) =>
             {
                tempCls.ShowMessage(obj);
             }) 不会阻塞调用线程,你能明白吗?

Launcher | 园豆:45050 (高人七级) | 2015-01-12 14:26

@Launcher: 我对线程一无所知,但是我昨天研究了一天也觉得是ThreadPool.QueueUserWorkItem((obj) =>
             {
                tempCls.ShowMessage(obj);
             })的问题,但是原理还是不懂

博学多思 | 园豆:76 (初学一级) | 2015-01-12 14:28

@博学多思: 如果你对线程都一无所知的话,那烦请你先找本《操作系统》的书学习下。

Launcher | 园豆:45050 (高人七级) | 2015-01-12 14:29

也就是说语句  tempCls.um = u 和 MessageBox.Show(um.UserName) 并不是按照 foreach (var u in userList) 顺序来执行的,而是乱序执行。

既然是乱序执行,为什么每次运行的结果都相同?

  ThreadPool.QueueUserWorkItem((obj) =>
             {
                tempCls.ShowMessage(obj);
             }) 不会阻塞调用线程

就是把这个方法将方法排入队列以便执行。 方法在有线程池线程变得可用时执行

 

博学多思 | 园豆:76 (初学一级) | 2015-01-12 14:48

@Launcher: MoveNext or Reset throws an InvalidOperationException.">枚举数没有对集合的独占访问权;因此,从头到尾对一个集合进行枚举在本质上不是一个线程安全的过程。 MoveNext and Current, Current returns the element that it is set to, even if the enumerator is already invalidated.">即使某个集合已同步,其他线程仍可以修改该集合,这会导致枚举数引发异常。 若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常

还是这个原因?

博学多思 | 园豆:76 (初学一级) | 2015-01-12 15:05

@博学多思: 既然是乱序执行,为什么每次运行的结果都相同? ——〉 这确实能证明你对线程一无所知。

和枚举没关系,就是简单的多线程问题。

Launcher | 园豆:45050 (高人七级) | 2015-01-12 15:37

@Launcher: 乱序执行:避免因为获取下一条程序指令所引起的处理器等待,取而代之的处理下一条可以立即执行的指令

当程序运行到:   ThreadPool.QueueUserWorkItem((obj) =>
             {
                tempCls.ShowMessage(obj);
             });

的时候,是直接运行下一次循环吗?求指教?当整个循环完事然后运行   ThreadPool.QueueUserWorkItem((obj) =>
             {
                tempCls.ShowMessage(obj);
             });?对不对?

博学多思 | 园豆:76 (初学一级) | 2015-01-12 15:50

@博学多思: 不是,是执行完 ThreadPool.QueueUserWorkItem 方法后执行 foreach (var u in userList) 语句。

Launcher | 园豆:45050 (高人七级) | 2015-01-12 15:55

@Launcher: 大侠,程序执行的顺序是不是这样:当程序运行到  tempCls.um = u; ThreadPool.QueueUserWorkItem(方法排入队列以便执行。 方法在有线程池线程变得可用时执行)新线程立即处理  tempCls.ShowMessage(obj);调用    Thread.Sleep(1000);
MessageBox.Show(um.UserName);原来的线程继续执行foreach 语句,因为变量在内部,所以最后只有一个值,这时重新排列单元将各执行单元结果按指令顺序重新排列,所以输出好几条zhangzetian???

博学多思 | 园豆:76 (初学一级) | 2015-01-12 18:55

@博学多思: 正确。

Launcher | 园豆:45050 (高人七级) | 2015-01-13 09:14

@Launcher: 非常感谢!

博学多思 | 园豆:76 (初学一级) | 2015-01-13 09:15
其他回答(1)
0

这是闭包的结果  

         foreach (var u in userList)
        {

 TempClass tempCls = new TempClass();
             tempCls.um = u;
 
             ThreadPool.QueueUserWorkItem((obj) =>
             {
                tempCls.ShowMessage(obj);
             });
        }

你再看看

隔壁老王来了 | 园豆:99 (初学一级) | 2015-01-12 15:17

这个就是我学习闭包的时候发现的问题,我不明白为什么调试和运行的结果不同?

支持(0) 反对(0) 博学多思 | 园豆:76 (初学一级) | 2015-01-12 15:20

@博学多思: 大哥 调试走的表象啊,跟没看是一样的,实际代码去看IL

支持(0) 反对(0) 隔壁老王来了 | 园豆:99 (初学一级) | 2015-01-12 15:24
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册