0

我有一些遗留代码在代码库中并被使用了几年,最近我们发现它的方法StopImmediately()根本没有阻止它。由于我对线程或后台工作人员所做的工作很少,因此我无法弄清楚它是如何工作的。

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

我不知道如何取消它..提前感谢您的帮助..

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

}

}

4

1 回答 1

0

BackgroundWorkera支持取消的典型方法是让DoWork事件处理程序定期检查BackgroundWorker' 的CancellationPending属性:

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. 它不会立即终止;做这项工作的人必须定期问“我现在应该退出还是继续?” 无论哪种方式,工作线程都会优雅地终止。

上面写的代码试图通过中止线程来立即终止后台工作者。这通常不是您想要的方式。理想情况下,应该更改此代码,以便作为doWork参数传入的函数定期检查取消请求。

但它不能按书面方式工作的主要原因是,currentThread直到调用函数之后才设置成员:doWork

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

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

它们应该如下翻转

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

然后它确实会立即(或多或少)不干净地终止。我建议阅读这篇 MSDN 文章,了解如何更好地支持取消BackgroundWorker.

希望这可以帮助!

于 2012-07-13T02:24:10.360 回答