我有一个线程调用其中的一个方法,现在这个方法执行一个查询,可能需要很长时间,可能需要40分钟左右才能完成。
我想给用户一个选择,让他们能够取消这个操作(即停止线程和停止查询以释放数据库)。
我应该提到,我正在使用 .net 4.5、SQL SERVER DB 和 C# 开发 WPF 应用程序。
我有一个线程调用其中的一个方法,现在这个方法执行一个查询,可能需要很长时间,可能需要40分钟左右才能完成。
我想给用户一个选择,让他们能够取消这个操作(即停止线程和停止查询以释放数据库)。
我应该提到,我正在使用 .net 4.5、SQL SERVER DB 和 C# 开发 WPF 应用程序。
void method(){
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged += worker_ProgressChanged;
worker.DoWork += worker_DoWork;
worker.WorkerSupportsCancellation = true;
if(!worker.IsBusy)
{
worker.RunWorkerAsync();
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do whatever needs to be done on the other thread here.
object argument = e.Argument; //if passed argument in RunWorkerAsync().
object result = new object();
e.Result = result;
//after making worker global, you can report progress like so:
worker.ReportProgress(50); //you can also pass a userState, which can be any object, to show some data already.
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//you can update a progress bar in here
int progress = e.ProgressPercentage;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//when done
}
void CancelTheTask()
{
if (worker.IsBusy)
{
//make worker global first, but then
worker.CancelAsync();
}
}
DoWork
方法中使用未在其中创建的资源。因此,将需要的内容作为参数传递给后台工作者。由后台工作者创建的东西也不应该设置为全局变量,应该通过结果传递。RunWorkCompleted
也会被触发。现在查询已经被执行了,所以即使应用程序失去了对它的所有资源,查询仍然在运行。使用任务并行库(TPL),您可以使用任务取消模式。
当您的线程被阻塞在等待查询时,它对停止任何操作都是无用的。
确保查询的SqlConnection可以从您的UI访问并关闭它。放弃该线程,它将终止(带有一个您必须抑制的错误)。
CancellationTokenSource ct;//instantiate it before ThreadPool.QueueUserWorkItem line
private void operation_Click(object sender, RoutedEventArgs e)
{
ct = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(_ =>
{
var result = LongTimeOperation();//set the operation in another thread so that the UI thread is kept responding
//use the Dispatcher to "return" to the UI thread
Dispatcher.BeginInvoke(new Action(() =>
{
//Use result for example : Label1.Text = result.ToString();
}));
});
}
CancellationTokenSource
,方法如下:private void cancel_Click(object sender, RoutedEventArgs e)
{
if (ct != null)
{
ct.Cancel();
ct= null;
}
}
注意:在 LongTimeOperation
() 中,您必须有一个额外的参数,类型为 CancellationToken
private float LongTimeOperation(CancellationToken ct)
{
if (ct.IsCancellationRequested)
return -1;
....
....
}
这个链接与托管线程中的取消
有关,非常有用。