简体   繁体   English

从主UI线程上的按钮挂起子线程

[英]Suspend a child thread from a button on the main UI thread

I've found this topic, How to suspend a thread by its name from the main thread? 我找到了这个主题, 如何通过主线程中的名称挂起一个线程? , but no satisfactory answer for what I'm trying to achieve. 但对于我想要实现的目标却没有令人满意的答案。

I'm using threading and the WatiN class to perform events on two browsers in the same windows form at the same time. 我正在使用线程和WatiN类同时在同一个窗口中的两个浏览器上执行事件。

I would like to, from the main UI thread, press a pause button available within one of the browsers that, through deriving the control name of the browser the pause button was pressed on, use that' name to figure out which sub-thread is associated with it's running logic, and pause that running logic until the play button is pressed. 我想从主UI线程中按下其中一个浏览器中的暂停按钮,通过导出按下暂停按钮的浏览器的控件名称,使用该名称来确定哪个子线程是与其运行逻辑相关联,并暂停运行逻辑,直到按下播放按钮。

Now today, we are so accomplished in terms of code and technology, there should be a way to do this. 现在,我们在代码和技术方面已经取得了很大成就,应该有办法做到这一点。

What do you think? 你怎么看?

Researching Ideas: 研究思路:

Pragmatically create ManualResetEvent and name it, use the UI pause button to grab the open browser control name, which is similiarly named after the child thread and browser control name (such a browser_5 & thread_5) to somehow target in on the MRE in the child thread, and close the gate to pause the logic. 实际创建ManualResetEvent并命名它,使用UI暂停按钮来获取打开的浏览器控件名称,该名称类似于子线程和浏览器控件名称(例如browser_5&thread_5),以某种方式定位在子线程中的MRE上,关闭门以暂停逻辑。 (But can this be done on child thread from the main UI thread?) (但这可以在主UI线程的子线程上完成吗?)

Don't use thread.Suspend 不要使用thread.Suspend

At first blush, it seems you could use thread.Suspend() to pause it and thread.Resume() to unpause it . 乍一看,似乎你可以使用thread.Suspend()来暂停它,并使用thread.Resume()来取消它 But this is not a very good idea. 但这不是一个好主意。 See the MSDN article for thread.Suspend for why you should never use it unless you intend to terminate the AppDomain for that thread. 有关thread.Suspend的MSDN文章,请参阅为什么不应该使用它,除非您打算终止该线程的AppDomain。

Do not use the Suspend and Resume methods to synchronize the activities of threads. 不要使用Suspend和Resume方法来同步线程的活动。 You have no way of knowing what code a thread is executing when you suspend it. 暂停它时,您无法知道线程正在执行的代码。 If you suspend a thread while it holds locks during a security permission evaluation, other threads in the AppDomain might be blocked. 如果在安全权限评估期间挂起线程时挂起线程,则可能会阻止AppDomain中的其他线程。 If you suspend a thread while it is executing a class constructor, other threads in the AppDomain that attempt to use that class are blocked. 如果在执行类构造函数时挂起线程,则会阻止AppDomain中尝试使用该类的其他线程。 Deadlocks can occur very easily. 死锁很容易发生。

A sub-loop would work, but isn't perfect 子循环可以工作,但并不完美

It isn't the best option, but you could use a similar technique to the one described in that question you linked . 它不是最佳选择,但您可以使用与您链接的问题中描述的技术类似的技术。

Instead of exiting the loop when a stop button is pressed, have it enter and wait inside a sub-loop while paused. 按下停止按钮时,不要退出循环,而是在暂停时进入子循环并等待。 Do a Thread.Sleep in that sub-loop to keep the CPU from pegging. 在该子循环中执行Thread.Sleep以防止CPU挂起。

This isn't the most efficient code possible, because it keeps the thread running, and hangs for another 100ms when resuming. 这不是最有效的代码,因为它使线程保持运行,并在恢复时再挂起100ms。

public class YourForm : Form
{
  private volatile bool _pause = false;

  private void StartButton_Click(object sender, EventArgs e)
  {
    var thread = new Thread(
      () =>
      {
        while (...)
        {
          // Periodically poll the _pause flag.
          while (_pause)
          {
            // Now that we're paused, wait until we're unpaused
            // before proceeding further in the outer loop
            Thread.Sleep(100);
          }

          // Todo: The rest of the processing here
        }
      });
    thread.Start();
  }

  private void PauseButton_Click(object sender, EventArgs e)
  {
    _pause = !_pause; // Toggle
  }
}

Use thread synchronization 使用线程同步

The best option is to use one of the various thread synchronization structures, like ManualResetEvent . 最好的选择是使用各种线程同步结构之一, ManualResetEvent Pausing threads is exactly what they're designed for. 暂停线程正是它们的设计目标。 They're very efficient because they are implemented with a mutex . 它们非常有效,因为它们是使用互斥锁实现的

public class YourForm : Form
{
  private volatile bool _pause = false;
  private static ManualResetEvent mre = new ManualResetEvent(true);

  private void StartButton_Click(object sender, EventArgs e)
  {
    var thread = new Thread(ThreadImplementation);
    thread.Start();
  }

  private void PauseButton_Click(object sender, EventArgs e)
  {
    _pause = !_pause;

    if(_pause)
    {
      mre.Reset();
    }
    else
    {
      mre.Set();
    }
  }

  private void ThreadImplementation()
  {
    while (...)
    {
      // Periodically wait on the event
      mre.WaitOne();

      // Todo: The rest of the processing here
    }
  }
}

Your ManualResetEvent idea is exactly correct. 您的ManualResetEvent想法完全正确。

Make the child threads WaitOne() on the event between each step. 在每一步之间的事件上让子线程WaitOne()
To pause the request, call Reset() ; 要暂停请求,请调用Reset() ; to unpause, call Set() . 要取消暂停,请调用Set()

If the event is set, WaitOne() will return immediately. 如果设置了该事件, WaitOne()将立即返回。

This will be much more efficient than repeated sleeps. 这比重复睡眠更有效。

I suspect that a ManualResetEventSlim would be slightly faster. 我怀疑ManualResetEventSlim会稍快一些。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM