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

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

上記のコードは、スレッドを中止することで、バックグラウンド ワーカーを即座に終了しようとします。これは通常、実行したい方法ではありません。理想的には、このコードを変更して、doWorkパラメーターとして渡された関数がキャンセル要求を定期的にチェックするようにする必要があります。

ただし、記述どおりに機能しない主な理由は、関数が呼び出されるcurrentThreadまでメンバーが設定されないことです。doWork

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

コールバックは渡された関数が完了するのを待ってからメンバーを割り当てるため、への呼び出しStopImmediately()は null スレッドを参照します。DoWorkdoWorkcurrentThread

次のように反転する必要があります

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

そして、それは確かに不潔に、そして(多かれ少なかれ)すぐに終了します。. _ _ BackgroundWorker_

お役に立てれば!

于 2012-07-13T02:24:10.360 に答える