2012-07-12 82 views
0

我有这样的遗留代码位于代码库中,并在过去几年中使用,最近我们发现它的方法StopImmediately()不会阻止它在所有。由于我对线程或后台工作人员所做的工作很少,因此我无法做出正确的工作方式。如何取消这排队的BackGroundworker

我想知道是否有经验丰富的线程家伙可以告诉我如何阻止这个令人困惑的小野兽完成任务。下面是完整的类(抱歉的代码量)

我无法弄清楚如何取消它..在此先感谢您的帮助..

using System; 
using System.Collections.Generic; 

using System.ComponentModel; 
using System.Threading; 
namespace GPS2.BackgroundWorkerEx 
{ 
public class QedBackgroundWorker 
{ 
    public QedBackgroundWorker() {} 

    Queue<object> Queue = new Queue<object>();   
    object lockingObject1 = new object(); 
    private Thread currentThread; 
    public delegate void WorkerCompletedDelegate<K>(K result, Exception error); 
    public object Arguments { get; set; } 


    /// <summary>  
    /// doWork is a method with one argument  
    /// </summary>  
    /// <typeparam name="T">is the type of the input parameter</typeparam>  
    /// <typeparam name="K">is the type of the output result</typeparam>  
    /// <param name="inputArgument"></param>  
    /// <param name="doWork"></param>  
    /// <param name="workerCompleted"></param>  
    public void RunAsync<T,K>(Func<T, K> doWork, T inputArgument, WorkerCompletedDelegate<K> workerCompleted)  
    {   
     BackgroundWorker bw = GetBackgroundWorker<T,K>(doWork, workerCompleted); 

     Queue.Enqueue(new QueueItem(bw, inputArgument));   
     lock (lockingObject1)   
     {    
      if (Queue.Count == 1)    
      {     
       ((QueueItem)this.Queue.Peek()).RunWorkerAsync(); 
       //currentThread = System.Threading.Thread.CurrentThread; 
      }   
     }  
    }  
    /// <summary>  
    /// Use this method if you don't need to handle when the worker is completed  
    /// </summary>  
    /// <param name="doWork"></param>  
    /// <param name="inputArgument"></param>  
    public void RunAsync<T,K>(Func<T, K> doWork, T inputArgument)  
    {   
     RunAsync(doWork, inputArgument, null);  
    } 

    private BackgroundWorker GetBackgroundWorker<T, K>(Func<T, K> doWork, WorkerCompletedDelegate<K> workerCompleted)  
    { 
     BackgroundWorker bw = new BackgroundWorker(); 

     bw.WorkerReportsProgress = false;   
     bw.WorkerSupportsCancellation = true;   
     bw.DoWork += (sender, args) =>{    
      if (doWork != null) 
      { 
       args.Result = (K)doWork((T)args.Argument); 
       currentThread = System.Threading.Thread.CurrentThread; 
      }   
     };   

     bw.RunWorkerCompleted += (sender, args) =>{    
      if (workerCompleted != null)    
      {     
       workerCompleted((K)args.Result, args.Error);    
      }    

      Queue.Dequeue();    

      lock (lockingObject1)    
      {     
       if (Queue.Count > 0)     
       {      
        ((QueueItem)this.Queue.Peek()).RunWorkerAsync();         
       }    
      }   
     };   
     return bw;  
    } 
    public void StopImmediately() 
    { 
     if (currentThread != null) 
      currentThread.Abort(); 
    } 


    public bool IsBusy() 
    { 
     ThreadState state = currentThread.ThreadState; 
     bool res = true; 
     switch (state) 
     { 
      case ThreadState.Running: 
       res = true; 
       break; 
      default: 
       res = false; 
       break; 
     } 
     return res; 
    } 

} 
public class QueueItem{  


    public QueueItem(BackgroundWorker backgroundWorker, object argument)  
    {   

     this.BackgroundWorker = backgroundWorker;   
     this.Argument = argument;  
    }  

    public object Argument { get; private set; }  
    public BackgroundWorker BackgroundWorker { get; private set; }  

    public void RunWorkerAsync()  
    {   
     this.BackgroundWorker.RunWorkerAsync(this.Argument);  
    }  

} 

}

回答

0

的典型方法对于BackgroundWorker支持取消对于DoWork事件处理程序来定期检查的BackgroundWorkerCancellationPending属性:

var worker = new BackgroundWorker(); 
worker.WorkerSupportsCancellation = true; 
worker.DoWork += (sender, args) => 
{    
    foreach (var thing in listOfThingsToDo) 
    { 
     if (worker.CancellationPending) 
     { 
      // Someone has asked us to stop doing our thing 
      break; 
     } 
     else 
     { 
      DoTheThing(thing); 
     } 
    } 
}; 

有人谁曾想取消BackgroundWorker,如果它正在运行,会叫

worker.CancelAsync(); 

这将导致它的CancellationPending属性设置为true,并造成当前正在运行,打破了其循环DoWork事件处理程序处理完当前的thing。它不会立即终止;做这项工作的人必须定期询问:“我现在应该退出还是继续前进?”无论哪种方式,工作线程都会优雅地终止。

上面写的代码试图通过中止线程立即终止后台工作。 This is usually not the way that you want to do it.理想情况下,应更改此代码,以便作为doWork参数传入的功能会定期检查取消请求。

但最主要的原因是因为写它不工作是,currentThread成员未设置直到doWork函数被调用:

bw.DoWork += (sender, args) => 
{ 
    if (doWork != null) 
    { 
     args.Result = (K)doWork((T)args.Argument); 
     currentThread = System.Threading.Thread.CurrentThread; 
    } 
}; 

StopImmediately()的调用将看到一个空线程,因为DoWork回调正在等待doWork传入的函数在分配currentThread成员之前完成。

如下

bw.DoWork += (sender, args) => 
{ 
    if (doWork != null) 
    { 
     currentThread = System.Threading.Thread.CurrentThread; 
     args.Result = (K)doWork((T)args.Argument); 
    } 
}; 

他们应该被翻转,然后它会立即确实(或多或少)不清洁终止和。我建议您阅读this MSDN article以获取如何在BackgroundWorker中更好地解决支持取消的示例。

希望这会有所帮助!

+0

干杯,确实有帮助..事实上,这一行“理想情况下,应更改此代码,以便作为doWork参数传入的函数定期检查取消请求。“我改变了runAsync <>方法返回一个BackGroundWorker BGWrk,在'传入'函数中添加'取消'处理,然后使用返回的BGWrk.CancelAsync()...我希望这是正确的,因为它似乎只是花花公子。 – snark 2012-07-13 04:01:11

+0

:-(毕竟不工作 - 回到第一个方格 – snark 2012-07-15 23:59:19