我找到了这个话题How to suspend a thread by its name from the main thread?,但对于我想要实现的目标却没有令人满意的答案。
我正在使用线程和WatiN类同时在同一窗体中的两个浏览器上执行事件。
我想从主UI线程中按下其中一个浏览器中的暂停按钮,通过导出按下暂停按钮的浏览器的控件名称,使用该名称来确定哪个子-thread与其运行逻辑相关联,并暂停运行逻辑,直到按下播放按钮。
现在,我们在代码和技术方面做得非常成功,应该有办法做到这一点。
您怎么看?
研究理念:
务实地创建ManualResetEvent并命名它,使用UI暂停按钮来获取打开的浏览器控件名称,该名称类似于子线程和浏览器控件名称(例如browser_5& thread_5)以某种方式定位在MRE上在子线程中,关闭门以暂停逻辑。 (但这可以在主UI线程的子线程上完成吗?)
答案 0 :(得分:3)
thread.Suspend
乍一看,您似乎可以use thread.Suspend()
to pause it和thread.Resume()
to unpause it。但这不是一个好主意。除非您打算终止该线程的AppDomain,否则请参阅the MSDN article for thread.Suspend
for why you should never use it。
不要使用Suspend和Resume方法来同步线程的活动。暂停它时,您无法知道线程正在执行的代码。如果在安全权限评估期间挂起线程时挂起线程,则可能会阻止AppDomain中的其他线程。如果在执行类构造函数时挂起线程,则会阻止AppDomain中尝试使用该类的其他线程。死锁很容易发生。
这不是最佳选择,但您可以使用与the one described in that question you linked类似的技巧。
当按下停止按钮时,不要退出循环,而是在暂停时进入并在子循环内等待。在该子循环中执行Thread.Sleep
以防止CPU挂起。
这不是最有效的代码,因为它可以保持线程运行,并在恢复时再挂起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
}
}
最好的选择是使用各种线程同步结构like ManualResetEvent
之一。暂停线程正是它们的设计目标。它们非常有效,因为它们是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
}
}
}
答案 1 :(得分:1)
您的ManualResetEvent
想法完全正确。
在每个步骤之间的事件中创建子线程WaitOne()
要暂停请求,请致电Reset()
;要取消暂停,请致电Set()
。
如果设置了该事件,WaitOne()
将立即返回。
这比重复睡眠更有效率。
我怀疑ManualResetEventSlim
稍快一点。