在按钮单击事件中中止长时间运行的线程

时间:2013-03-26 12:52:33

标签: c# wpf multithreading

在我的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(); 
    }

但该线程不会中止并继续该过程。请给我你宝贵的建议。

3 个答案:

答案 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