如何在WPF中终止调度的线程

时间:2013-03-03 17:01:54

标签: wpf multithreading dispatcher

我有一个简单且非常直观的WPF,当我点击开始时,它将开始工作,如果我点击停止,它将停止。启动worker / background线程的代码是:

--- variables ---
Thread[] thd;
bflag = false;

--- Start background worker when Start button is clicked ---
private void btnStart_Click(object sender, RoutedEventArgs e)
{
   Thread startFileCopy = new Thread(() => startFC());
   startFileCopy.Start();  
}

--- StartFC code ---
private void startFC()
{
   bflag = true;
   thd = new Thread[3];
   for(int i=0; i<3; i++)
   {
      thd[i] = new Thread(copynow);
      thd[i].Start();
   }
}

--- copynow code ---
private void copynow()
{
   while(bflag)
   {
      if (filecount == 0)
        bflag = false;
      else
      {
         // --- copy file ---
         Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
               new Action(() => copyFile(<filename to be copied>)));
         // --- update progressbar ---
         Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
               new Action(() => updateProgressbar(++1)));
      }
   }
}

现在停止此操作,在我的取消按钮上,我调度了另一个发送优先级的线程,将bflag设置为false。但是,根据我的UI上的响应,进度条仍在更新,文件复制仍在继续。我的停止按钮的代码:

--- Stop when stop button is clicked ---
private void btnStop_Click(object sender, RoutedEventArgs e)
{
   Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Send, 
              new Action(() => stopThreads()));
}

--- stopThreads code ---
private void stopThreads()
{
   bflag = false;
   if (thd != null)
     for (int i = 0; i < THREAD_COUNT; i++)
       if (thd[i].IsAlive)
          thd[i].Join(3000);
}

我做错了什么?提前谢谢!

1 个答案:

答案 0 :(得分:2)

你的线程方法的问题是它反复启动copyFile BeginInvoke方法的异步执行:

// --- copy file ---
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
    new Action(() => copyFile(<filename to be copied>)));

这会在Dispatcher队列上创建许多排队等待执行的操作。即使你的线程被停止,仍然有很多这些排队的操作,这使你认为该线程仍在运行。

您需要以在线程方法中实际执行复制操作的方式更改代码:

private void copynow()
{
    while (bflag && filecount > 0)
    {
        copyFile(<filename to be copied>);

        // update progressbar by synchronous Invoke instead of BeginInvoke
        Application.Current.Dispatcher.Invoke(
            new Action(() => updateProgressbar(++1)));
    }
}