在我的WPF应用程序中,我有一个长时间运行的过程,使用BlueBeam Q Server将文件转换为PDF。当进程发生时,它不应该冻结,因此编写下面的代码来处理:
private void btn_convert_Click(object sender, RoutedEventArgs e)
{
thread = new Thread(new ThreadStart(WorkerMethod));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Name = "PDF";
thread.Start();
}
WorkerMethod()
{
//code to connect to Q server and conversion goes here
}
现在,当流程开始时,用户可以看到取消按钮。当用户按下取消时,我想中止启动的线程。我编写了如下代码:
private void btn_cancel_Click(object sender, RoutedEventArgs e)
{
if (thread.Name == "PDF")
thread.Abort();
}
但该线程不会中止并继续该过程。请给我你宝贵的建议。
答案 0 :(得分:4)
您应该尽可能避免使用Abort
。搜索SO以了解如何优雅地取消线程 - 当线程代码调用您无法影响的其他代码时,无法完成此操作,例如第三方库方法或类似方法。
例如,如果您的线程方法执行如下操作:
WorkerMethod()
{
CallFunctionInExternalDLL();
}
它无法正常中止。
取消"取消"这样一个线程,最好向线程指示它应该取消(例如使用bool
标志)并让线程回滚其结果(例如,删除创建的PDF或类似的东西)那)。然后,您的应用程序可以继续,就好像线程从未启动过一样。
例如,您的代码可能如下所示:
WorkerMethod()
{
CallFunctionInExternalDLL();
if (m_threadAborted)
RollBackWhatFunctionDid();
}
如果您的主题看起来像这样:
WorkerMethod()
{
while (true)
{
CallFunctionInExternalDLL();
}
}
你可以这样做:
WorkerMethod()
{
while (!m_threadAborted)
{
CallFunctionInExternalDLL();
}
if (m_threadAborted)
RollBackStuff();
}
在这些示例中,m_threadAborted
是一个bool
标志,声明如下:
private volatile bool m_threadAborted = false;
答案 1 :(得分:1)
您可以使用Backgroundworker而不是Thread,如果您的代码包含循环(您必须在每个循环中测试一个布尔属性),您将能够取消它
// define the backgroundWorker
this.backgroundWorker.DoWork += new DoWorkEventHandler(this.BackgroundWorker_DoWork);
this.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.BackgroundWorker_RunWorkerCompleted);
this.backgroundWorker.WorkerSupportsCancellation = true;
// execute process
this.backgroundWorker.RunWorkerAsync();
// cancel process
this.backgroundWorker.CancelAsync();
并在您的BackgroundWorker_DoWork代码中:
// in a loop
if (this.backgroundWorker.CancellationPending == false)
{
...
}
答案 2 :(得分:1)
您可以使用此处所述的CancellationTokenSource:
http://msdn.microsoft.com/en-us/library/dd997364.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
static void CancelWithThreadPoolMiniSnippet()
{
//Thread 1: The Requestor
// Create the token source.
CancellationTokenSource cts = new CancellationTokenSource();
// Pass the token to the cancelable operation.
ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), cts.Token);
// Request cancellation by setting a flag on the token.
cts.Cancel();
}
//Thread 2:The Listener
static void DoSomeWork(object obj)
{
CancellationToken token = (CancellationToken)obj;
for (int i = 0; i < 100000; i++)
{
// Simulating work.
Thread.SpinWait(5000000);
if (token.IsCancellationRequested)
{
// Perform cleanup if necessary.
//...
// Terminate the operation.
break;
}
}
}
这篇文章描述了其他可能的方式:
Question about terminating a thread cleanly in .NET