首页 新闻 会员 周边

线程停止的奇怪问题

1
悬赏园豆:10 [已解决问题] 解决于 2010-08-15 21:54

       1.

---------------------------

   /// <summary>
        /// 用来判断是否停止线程的变量
        /// </summary>
        private  volatile bool m_stopThread=false;
        private Thread m_threadStartSendMusic;

        /// <summary>
        /// 开始发送
        /// </summary>
        public void SendMusicInThread(int startcount,int sendcount,string sbip)
        {
            //若有在发送数据 停止发送
            m_stopThread = true;
            Thread.Sleep(106);
         
          
            m_StartCount = startcount;
            m_SendCount = sendcount;
            m_sbip = sbip;
            //新开一个线程发送数据 
            m_threadStartSendMusic = new Thread(SendMusic);
            m_threadStartSendMusic.IsBackground = true;
            m_threadStartSendMusic.Start();
        }

        /// <summary>
        /// 发送音乐
        /// </summary>
        private  void SendMusic()
        {
            m_stopThread = false;
         
            int endCount = m_StartCount + m_SendCount;
            for (int i = m_StartCount; i < endCount; i++)
            {
                if (m_stopThread)
                {
                    break;
                }

             //do something
             }

      }

----------------------------------------------------------------------------------------------

2.

        /// <summary>
        /// 用来判断是否停止线程的变量
        /// </summary>
        private  volatile bool m_stopThread=false;
        private Thread m_threadStartSendMusic;

        /// <summary>
        /// 开始发送
        /// </summary>
        public void SendMusicInThread(int startcount,int sendcount,string sbip)
        {
            //若有在发送数据 停止发送
            m_stopThread = true;
            Thread.Sleep(106);
            m_stopThread = false;
           
            m_StartCount = startcount;
            m_SendCount = sendcount;
            m_sbip = sbip;
            //新开一个线程发送数据 
            m_threadStartSendMusic = new Thread(SendMusic);
            m_threadStartSendMusic.IsBackground = true;
            m_threadStartSendMusic.Start();
        }

        /// <summary>
        /// 发送音乐
        /// </summary>
        private  void SendMusic()
        {
            int endCount = m_StartCount + m_SendCount;
            for (int i = m_StartCount; i < endCount; i++)
            {
                if (m_stopThread)
                {
                    break;
                }

             //do something
             }

      }

-------------------------------------------------------------------------------------------------

 

当我多次执行SendMusicInThread(。。。)方法时 为何1不能停止当前线程 然后再开线程m_threadStartSendMusic  

2却能把上一个线程停掉 然后再开一个线程 

就 m_stopThread 放的位置不同

而m_stopThread 我设置的是volatile 应该每次执行去判断m_stopThread的时候都是最新的值才对 为什么呢

 

 

问题补充: Thread td; List<Test> list_test = new List<Test>(); private void button1_Click(object sender, EventArgs e) { //填充数据  if (list_test.Count < 4) { Test t; for (int i = 0; i < 5; i++) { t = new Test(); t.sbcode = i; list_test.Add(t); } } td = new Thread(dd); td.Start(); } private void dd() { int cout = 0; while (true) { //当我把这个sleep里面的值设置的大一点的时候 不会出现我说的这情况 Thread.Sleep(1); Test c_test = list_test.Find(p => p.sbcode == 3); if (c_test != null) { c_test.SendMusicInThread(); } //执行四次 退出循环 测试用的  cout++; if (cout > 4) break; } } public class Test { public int sbcode { get; set; } /// <summary> /// 用来判断是否停止线程的变量 /// </summary> private volatile bool m_stopThread = false; private Thread m_threadStartSendMusic; public void SendMusicInThread() { //设置 当为true时 退出SendMusic m_stopThread = true; Thread.Sleep(6); //把m_stopThread放在这里时 一定会退出  //m_stopThread=flase //开一个线程 m_threadStartSendMusic = new Thread(SendMusic); m_threadStartSendMusic.Start(); } /// <summary> /// 执行线程里的数据 /// </summary> private void SendMusic() { //把false的值放在这里面 线程不一定会退出 
半调子的主页 半调子 | 初学一级 | 园豆:10
提问于:2010-08-13 16:42
< >
分享
最佳答案
0

你是如何调用 SendMusicInThread 这个函数的?

Thread.Sleep() 时间长点,比如 5000。

收获园豆:10
Launcher | 高人七级 |园豆:45045 | 2010-08-13 17:08
sleep无论设置多长都没用  是在主线程中调用 如果不是在线程中调用 无论1还是2方法都是可以结束先前面的那个线程
半调子 | 园豆:10 (初学一级) | 2010-08-14 09:15
@半调子:能不能给个完整的示例,因为我在button_click中调用 SendMusicInThread,两种方式都没问题,当然,这并不是说我以高频调用SendMusicInThread的时候不会不出现问题。
Launcher | 园豆:45045 (高人七级) | 2010-08-14 11:40
发给你了 上面写的不够放
半调子 | 园豆:10 (初学一级) | 2010-08-14 16:09
@半调子:我把你给的例子修改了下: private void dd() { Test c_test = list_test.Find(p => p.sbcode == 3); for (int i = 0; i < 10; i++) { c_test.SendMusicInThread(); } } 和你的是一致的,只是为了测试。 volatile 只能保证每次从内存重新读取值(而不是从寄存器读取快照),但是不能保证m_stopThread的赋值是顺序的。因此,当你以高频率调用SendMusicInThread时,你不能保证前一次调用对 m_stopThread = true后,后一次调用一定是在前一次调用使用 if (m_stopThread) 之后或者之前才执行 m_stopThread = true. 你的两种 m_stopTread = false 放置,有比较大的差异就在于,第二种方式有更多的机会在 if(m_stopThread) 之前就有别的调用执行了 m_stopThread = true.对于你的第一种方式,最坏的情况就是所有调用都同时执行了 m_stopThread = true ,然后有一个或多个线程执行了 m_stopThread = false 后,就没有线程被停止。 因此,你要停掉前一次的线程,不能通过一个 volatile 来保证,在多线程调用下,你必须使用lock把创建线程的语句锁定,如下: private readonly object _workerLoker = new object(); public void SendMusicInThread() { // 保证第一次线程创建只执行一次。 if (this.m_threadStartSendMusic == null) { lock (this._workerLoker) { if (this.m_threadStartSendMusic == null) { m_threadStartSendMusic = new Thread(SendMusic); m_threadStartSendMusic.Start(); return; } } } // 保证始终只有前一个线程停止后,再启动新的线程。 // 此操作将阻塞调用 SendMusicInThread 的线程。 // m_stopThread 将只会在这里被设置。 lock (this._workerLoker) { // 1,通知前一个线程应该停止工作; this.m_stopThread = true; // 2,等待前一个线程退出; this.m_threadStartSendMusic.Join(); // 3,开始一个新的线程; this.m_stopThread = false; m_threadStartSendMusic = new Thread(SendMusic); m_threadStartSendMusic.Start(); } }
Launcher | 园豆:45045 (高人七级) | 2010-08-14 19:26
另外,我有个建议,你不应该把线程作为单元来调度,你应该把你的任务作为单元来调度,也就是为你的 Test 类放置一个队列 Queue,然后开启一个线程从队列读取任务,当有新的任务进入队列时,就通知线程从队列读取一个新的任务去执行。
Launcher | 园豆:45045 (高人七级) | 2010-08-14 19:30
受益非浅 非常感谢
半调子 | 园豆:10 (初学一级) | 2010-08-15 21:52
其他回答(1)
0

start方法后,线程不会马上被执行,而是等待被执行。我猜想哦,这两段代码在不同配置电脑上,会有不同结果。

James Lu | 园豆:195 (初学一级) | 2010-08-13 17:31
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册