【问题标题】:Abort long running thread in button click event在按钮单击事件中中止长时间运行的线程
【发布时间】:2013-03-26 21:14:23
【问题描述】:

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

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

【问题讨论】:

  • 你能给我们你的WorkerMethod的代码吗? Thorsten Dittmar 所说的是正确的,但根据您连接到“Q 服务器”的方式,您可能可以简单地放弃请求。

标签: c# wpf multithreading


【解决方案1】:

您应该尽可能避免使用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;

【讨论】:

    【解决方案2】:

    您可以使用 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)
    {
    ...
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用此处所述的 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-13
        • 2014-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多