[英]How to cancel this Queued BackGroundworker
我有一些遗留代码,它们已经存在于代码库中并在过去的几年中被使用,最近,我们发现它的方法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);
}
}
}
BackgroundWorker
支持取消的典型方法是让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
参数传入的函数定期检查取消请求。
但是,它不能按书面形式工作的主要原因是直到调用doWork
函数之后才设置currentThread
成员:
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);
}
};
然后它确实会不干净地(或多或少)立即终止。 我建议阅读此MSDN文章 ,以获取如何更好地支持BackgroundWorker
取消的示例。
希望这可以帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.