【问题标题】:Stopping work from one thread using another thread使用另一个线程从一个线程停止工作
【发布时间】:2010-06-18 16:11:15
【问题描述】:

不确定我的标题是否用词好,但无论如何:)

我有两个线程:一个包含需要完成的工作的主线程,以及一个包含带有进度条和取消按钮的表单的工作线程。在普通代码中,情况正好相反,但在这种情况下我不能这样做。

当用户单击取消按钮时,会显示一个提示,询问他是否真的要取消工作。问题是主线程上的工作仍在继续。我可以让主线程停止工作等,但我希望当他在提示上单击“是”时它停止工作。

例子:

// Main thread work starts here    
    t1 = new Thread(new ThreadStart(progressForm_Start));
    t1.Start();

    // Working
    for (i = 0; i <= 10000; i++)
    {
        semaphore.WaitOne();
        if (pBar.Running)
            bgworker_ProgressChanged(i);
        semaphore.Release();
        if (pBar.IsCancelled) break; 
    }

    t1.Abort(); 
// Main thread work ends here

// Start progress bar form in another thread
void progressForm_Start()
{
    pBar.Status("Starting");
    pBar.ShowDialog();
}

理论上我可以在 cancelWatch() 函数中包含一个提示,但是我必须在我实现这个类的任何地方都这样做。

【问题讨论】:

  • 为什么不能将表单放在主线程中,而只使用 Swing WorkerThread 呢?这看起来很复杂。还有你所说的“普通代码”是什么意思
  • 我所说的“普通代码”是指我一开始会怎么想。我不能将表单放在主线程中,因为我需要能够随时单击“取消”按钮来取消操作。但是我不能使用 BackgroundWorker,因为我不想在这里使用异步线程。主线程已经是一个显示数据并在后台做一些事情的表单。我需要一个进度条和一个取消按钮,而在主窗体上做这件事几乎是不可能的。

标签: c# multithreading


【解决方案1】:

我有几个快速的 cmets:

  1. 避免使用Thread.Abort()here's why
  2. 使您的线程成为后台线程:Thread.IsBackground = true(这将在您的应用退出时自动退出线程)。

这里是关于如何安全地停止线程运行的详细讨论:Is it safe to use a boolean flag to stop a thread from running in C#

要停止主线程上的工作,您必须执行以下操作:

boolean volatile isRunning = true;

static void Main(...)
{
    // ...
    // Working
    for (i = 0; i <= 10000; i++)
    {
        semaphore.WaitOne();
        if (!isRunning) break; // exit if not running
        if (pBar.Running)
            bgworker_ProgressChanged(i);
        semaphore.Release();
    }
    //...
    t1.Interrupt();// make the worker thread catch the exception
}
// 
void cancelButton_Click(object sender, EventArgs e)
{
    isRunning = false; // optimistic stop
    semaphore.Release();
}

【讨论】:

  • 好的,谢谢。有机会我一定要试试这个。
  • 对不起,我没有回复您...我们决定尝试不同的路线,但感谢您的回答。它至少为我们指明了正确的方向:)
  • @Duracell,我很高兴我的回答在某些方面有所帮助:)。
【解决方案2】:

我推荐使用CancellationTokenSource,它可以处理这种复杂的场景。它是任务并行库的一部分,但实际上不必与Task 对象一起使用;它可以很容易地与旧式 Thread 对象一起使用。

当然,如果你有时间,我建议将主线程的工作定义为 Task 对象(使用 TaskScheduler.FromCurrentSynchronizationContext 在主 UI 线程上运行)。

请注意,以上所有内容均假定为 .NET 4.0。如果您仍然停留在旧平台上,您只需要拥有一个受lock 或类似东西保护的bool cancelled; 字段。提示:请勿拨打Thread.Abort;这是邪恶的。

【讨论】:

  • 不幸的是,我们被困在 .NET 3.5 上,因为这正是我所需要的 :( ...无论如何谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多