【问题标题】:Abort a thread which is running a long query中止正在运行长查询的线程
【发布时间】:2015-06-06 06:36:09
【问题描述】:

我有一个调用其中一个方法的线程,现在这个方法执行一个查询可能需要很长时间,可能需要 40 分钟左右才能完成,

我想给用户一个选择来取消这个操作(意味着停止线程并停止查询以释放数据库)。

我应该提到我正在使用 .net 4.5、SQL SERVER DB 和 C# 开发 WPF 应用程序。

【问题讨论】:

  • 你应该使用 BackgroundWorker。它允许取消。

标签: c# wpf multithreading abort


【解决方案1】:

你应该使用backgroundworker,这正是你想要的。

Eather 从工具箱拖放它或在代码后面创建它。它支持取消、报告进度、完成时通知并知道它是否正在运行。

这是一个例子。

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 方法中使用不是在其中创建的资源。因此,将后台工作人员中需要的东西作为参数传递。并且后台工作者创建的东西不应该设置为全局变量ether,通过结果传递。

取消时,RunWorkCompleted 也会被触发。现在对数据库的查询已经在执行,所以它仍在运行,即使您的应用程序丢失了所有资源。

要取消它,我们需要知道您如何执行查询,例如提到的@S.Akbari 是一种方法。 Entity Framework 6 也支持取消。

为此:check this when using Queryable

here is another example

或者这个没有实体框架的solution

【讨论】:

  • 这不是他想要的,这不会取消一个查询
  • 绝对正确,亨克!没有正确阅读,我已经用一些已经给出的解决方案编辑了我的答案。走吧
【解决方案2】:

使用Task Parallel Library (TPL),您可以使用Task Cancellation 模式。

【讨论】:

  • 如果后台进程积极配合取消并定期检查它,这是一个不错的选择,但如果不是这种情况,您需要更激进的方法。
【解决方案3】:

当您的线程在等待查询时被阻塞时,停止任何事情都是无用的。

确保可以从您的 UI 访问查询的 SqlConnection 并关闭它。放弃线程,它将终止(您必须抑制一个错误)。

【讨论】:

    【解决方案4】:

    如果 UI 线程正在执行长时间操作,它将无法处理 用户界面请求。这也称为无响应。 像这样使用ThreadPool

    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;
        ....
        ....
    }
    

    这个link 对托管线程中的Cancellation 很有用。

    【讨论】:

      【解决方案5】:

      这是一个常见问题。但在WPFWinForm 中,我想使用BackGroundWorker。见Here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-12
        • 1970-01-01
        • 2018-08-12
        相关资源
        最近更新 更多