none
多线程无法终止线程,这种情况应该怎么办? RRS feed

  • 问题

  • 我用多线程去完成一个任务,但是工作时需要终止作务,对多线程使用循环的th[i].Abort(); 来停止线程,大部分情况可以成功。但有时完全无效任务仍然继续执行着,这样的情况会是什么方面的问题,以及如何解决。小弟真的很急希望可以给个方案。

    由于代码太多太长不方便上似,希望高手帮我想想会是什么方面问题,小好弟去排除查证。谢谢

     
    2012年8月15日 2:19

答案

  • Hi 风灵波,

      ManualEventReset是用来手动开启过后终止信号量,实例时设置为False则线程一开始是停止,要Set方法来开启。 如果是True则一开始线程是运行的。Reset方法用来改变状态,如果是停止状态可以在回调时候用WaitOne来开启。AutoEventReset则是每个脉冲都会发生一次线程,有点类似正向电平脉冲一样。

     


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2012年8月16日 6:08
    版主
  • 谢谢楼上高人,但是我用的是net 3.5所以task应该用不上。

    2)使用AutoEventReset或者ManualEventReset(信号机制)+线程(后台),直到任务完成后告知主程序。

    信号量不也就是控制线程与资源同步而以,它怎么控制线程终止。。。这个问题感觉好严重啊

    那么你可以使用BackGroundWorker类:

    其中设置:

    1)WorkerSupportsCancellation =true(支持取消)

    2)调用CancelAsync然后取消。

    3)具体请查看示例:

    http://msdn.microsoft.com/zh-cn/library/4852et58(v=vs.80)


    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年8月16日 7:06
    版主
  • 以下是我的示例:

    namespace CSharp
    {
        public partial class Form1 : Form
        {
            private BackgroundWorker bw = new BackgroundWorker();
    
            public Form1()
            {
                InitializeComponent();
                bw.WorkerReportsProgress = true;    //支持向主窗体回报情况
                bw.WorkerSupportsCancellation = true;   //支持取消
                bw.DoWork += bw_DoWork;
                bw.ProgressChanged += bw_ProgressChanged;
                bw.RunWorkerCompleted += bw_RunWorkerCompleted;
            }
    
            void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                MessageBox.Show("任务完成!");
            }
    
            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                progressBar1.Value = e.ProgressPercentage;
            }
    
            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
                int i = 0;
                Random r = new Random(Guid.NewGuid().GetHashCode());
                while (i<100)
                {
                    if (bw.CancellationPending)
                    {
                        MessageBox.Show("终止任务");
                        break;
                    }
                    i += 10;
                    bw.ReportProgress(i, null);
                    Thread.Sleep(r.Next(500, 5000));
                }
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                 bw.RunWorkerAsync();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                bw.CancelAsync();
            }
        }
    }


    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年8月16日 7:26
    版主

全部回复

  • Thread.Abort不一定立即终止线程(参考:http://msdn.microsoft.com/zh-cn/library/ty8d3wta.aspx)

    解决方法:

    1)尝试先调用Suspend,然后Abort(由于Suspend已经过时,不是很推荐)。

    2)使用AutoEventReset或者ManualEventReset(信号机制)+线程(后台),直到任务完成后告知主程序。

    3)使用net4.0的Task,示例代码(控制台下):

    public class Program
        {
            static void Main(string[] args)
            {
                Random r = new Random(Guid.NewGuid().GetHashCode());
                CancellationTokenSource csource = new CancellationTokenSource();
                Task t1 = new Task(() =>
                {
                    while (true)
                    {
                        Console.WriteLine("子线程在运行……");
                        Thread.Sleep(r.Next(500, 5000));
                    }
                },csource.Token);
                t1.Start();
    
                
                //主线程
                Console.WriteLine("按任意键停止子线程运行……");
                Console.Read();
                csource.Cancel(true);
                Console.WriteLine("子线程被终止……");
            }
        }

    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年8月15日 2:46
    版主
  • 谢谢楼上高人,但是我用的是net 3.5所以task应该用不上。

    2)使用AutoEventReset或者ManualEventReset(信号机制)+线程(后台),直到任务完成后告知主程序。

    信号量不也就是控制线程与资源同步而以,它怎么控制线程终止。。。这个问题感觉好严重啊

    2012年8月15日 12:57
  • Hi 风灵波,

      ManualEventReset是用来手动开启过后终止信号量,实例时设置为False则线程一开始是停止,要Set方法来开启。 如果是True则一开始线程是运行的。Reset方法用来改变状态,如果是停止状态可以在回调时候用WaitOne来开启。AutoEventReset则是每个脉冲都会发生一次线程,有点类似正向电平脉冲一样。

     


    Jason Wang [MSFT]
    MSDN Community Support | Feedback to us

    2012年8月16日 6:08
    版主
  • 谢谢楼上高人,但是我用的是net 3.5所以task应该用不上。

    2)使用AutoEventReset或者ManualEventReset(信号机制)+线程(后台),直到任务完成后告知主程序。

    信号量不也就是控制线程与资源同步而以,它怎么控制线程终止。。。这个问题感觉好严重啊

    那么你可以使用BackGroundWorker类:

    其中设置:

    1)WorkerSupportsCancellation =true(支持取消)

    2)调用CancelAsync然后取消。

    3)具体请查看示例:

    http://msdn.microsoft.com/zh-cn/library/4852et58(v=vs.80)


    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年8月16日 7:06
    版主
  • 以下是我的示例:

    namespace CSharp
    {
        public partial class Form1 : Form
        {
            private BackgroundWorker bw = new BackgroundWorker();
    
            public Form1()
            {
                InitializeComponent();
                bw.WorkerReportsProgress = true;    //支持向主窗体回报情况
                bw.WorkerSupportsCancellation = true;   //支持取消
                bw.DoWork += bw_DoWork;
                bw.ProgressChanged += bw_ProgressChanged;
                bw.RunWorkerCompleted += bw_RunWorkerCompleted;
            }
    
            void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                MessageBox.Show("任务完成!");
            }
    
            void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                progressBar1.Value = e.ProgressPercentage;
            }
    
            void bw_DoWork(object sender, DoWorkEventArgs e)
            {
                int i = 0;
                Random r = new Random(Guid.NewGuid().GetHashCode());
                while (i<100)
                {
                    if (bw.CancellationPending)
                    {
                        MessageBox.Show("终止任务");
                        break;
                    }
                    i += 10;
                    bw.ReportProgress(i, null);
                    Thread.Sleep(r.Next(500, 5000));
                }
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                 bw.RunWorkerAsync();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                bw.CancelAsync();
            }
        }
    }


    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年8月16日 7:26
    版主