1

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

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

4

3 回答 3

4

你应该尽可能避免Abort。搜索如何优雅地取消线程 - 当线程代码调用您无法影响的其他代码时无法完成,例如第三方库方法或类似的东西。

例如,如果您的线程方法执行以下操作:

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;
于 2013-03-26T12:55:48.927 回答
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;
        }
    }
}

这篇文章描述了其他可能的方法:
关于在 .NET 中干净地终止线程的问题

于 2013-03-26T13:04:32.147 回答
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)
{
...
}
于 2013-03-26T12:55:41.557 回答