none
程序运行和调试的问题 RRS feed

  • 问题

  • 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);
                 });
            }

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

    please verify my account

    2015年1月12日 10:33

答案

  • 你好:

    我建议你下次发布问题的时候把你的测试代码贴出来,这样的话别人可以更容易重现你的问题。

    在这段代码中,如果直接执行的话都会显示出最后一个UserName,原因是在循环遍历userList的时候从线程池中抓取了三个线程,这三个线程执行的方法引用的是同一个对象tempCls。而在MessageBox.Show被执行之前线程暂停了一秒,这一秒之内三个线程同时启动了,并且tempCls.um对象在这一秒之内也被最终赋值为最后一个UserName。1秒钟之后MessageBox.Show执行了,引用的UserName是同一个字符串。

    而调试的过程中,人为的干预了线程池中线程抓取的时机,导致MessageBox.Show引用的um.UserName可能不一样。

    我建议你看一下线程池的相关概念:

    http://msdn.microsoft.com/en-us/library/0ka9477y(v=vs.110).aspx


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 lctk 2015年1月13日 10:33
    2015年1月13日 3:04
    版主

全部回复

  • 你好:

    我建议你下次发布问题的时候把你的测试代码贴出来,这样的话别人可以更容易重现你的问题。

    在这段代码中,如果直接执行的话都会显示出最后一个UserName,原因是在循环遍历userList的时候从线程池中抓取了三个线程,这三个线程执行的方法引用的是同一个对象tempCls。而在MessageBox.Show被执行之前线程暂停了一秒,这一秒之内三个线程同时启动了,并且tempCls.um对象在这一秒之内也被最终赋值为最后一个UserName。1秒钟之后MessageBox.Show执行了,引用的UserName是同一个字符串。

    而调试的过程中,人为的干预了线程池中线程抓取的时机,导致MessageBox.Show引用的um.UserName可能不一样。

    我建议你看一下线程池的相关概念:

    http://msdn.microsoft.com/en-us/library/0ka9477y(v=vs.110).aspx


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 lctk 2015年1月13日 10:33
    2015年1月13日 3:04
    版主
  • 你好,我的问题是这样的,可以吧  Thread.Sleep(1000);注释掉

    设置断点运行结果:三个不同jiejiep,xiaoyi,zhangzetian

    不设置断点直接运行zhangzetian,zhangzetian,zhangzetian


    please verify my account

    • 已编辑 lctk 2015年1月13日 5:42
    2015年1月13日 4:58
  • public partial class Form1 : Form
        {

            public class UserModel
            {
                public string UserName
                {
                    get;
                    set;
                }

                public int UserAge
                {
                    get;
                    set;
                }
            }

            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);
                }
            }


            public Form1()
            {
                InitializeComponent();
                TempClass tempCls = new TempClass();
                foreach (var u in userList)
                {
                    tempCls.um = u;

                    ThreadPool.QueueUserWorkItem((obj) =>
                    {
                        tempCls.ShowMessage(obj);
                    });
                }
            }
        }

    please verify my account

    2015年1月13日 7:51
  • 问题就在于你在show用户名之前让线程暂停了1秒,在这1秒之内3个线程所指向的同一个对象tempCls.um经过三次遍历被赋值为"zhangzetian". 如果不添加Thread.Sleep这句代码的话,有可能ShowMessage的时候才遍历第一次,show出来的就是第一个用户名,也有可能才遍历第二次,那么show出来的就是第二个用户名。

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    2015年1月13日 8:45
    版主
  • 多谢解答,解释得很精确

    please verify my account

    2015年1月13日 10:33