Reputation: 6020
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.
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.
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. (But can this be done on child thread from the main UI thread?)
Upvotes: 1
Views: 742
Reputation: 59131
thread.Suspend
At first blush, it seems you could use thread.Suspend()
to pause it and thread.Resume()
to unpause it. 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.
Do not use the Suspend and Resume methods to synchronize the activities of threads. 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. 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. Deadlocks can occur very easily.
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.
This isn't the most efficient code possible, because it keeps the thread running, and hangs for another 100ms when resuming.
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
}
}
The best option is to use one of the various thread synchronization structures, like 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
}
}
}
Upvotes: 3
Reputation: 887777
Your ManualResetEvent
idea is exactly correct.
Make the child threads WaitOne()
on the event between each step.
To pause the request, call Reset()
; to unpause, call Set()
.
If the event is set, WaitOne()
will return immediately.
This will be much more efficient than repeated sleeps.
I suspect that a ManualResetEventSlim
would be slightly faster.
Upvotes: 1