Thread.Resume is Obsolete? How are we supposed to wake up SleepingThreads now?

B

Benny Raymond

I have a thread that sleeps for 5 minutes once it's finished running a
method and then it repeats itself if it's supposed to (bool = true).
Prior to 2.0 I was able to resume the thread after marking the bool to
false which would cause the thread to finish what it was doing and
complete, or to wake up for it's sleep state and not loop back into
itself anymore.

How do we tell a thread to stop sleeping now that Thread.Resume is obsolete?
 
J

Jon Skeet [C# MVP]

Benny said:
I have a thread that sleeps for 5 minutes once it's finished running a
method and then it repeats itself if it's supposed to (bool = true).
Prior to 2.0 I was able to resume the thread after marking the bool to
false which would cause the thread to finish what it was doing and
complete, or to wake up for it's sleep state and not loop back into
itself anymore.

How do we tell a thread to stop sleeping now that Thread.Resume is obsolete?

You use Monitor.Wait/Pulse or WaitHandles, which is what you should
have been doing before :)

See http://www.pobox.com/~skeet/csharp/threads/deadlocks.shtml (half
way down) for a sample of this.

Jon
 
A

Abubakar

Also dont use Thread::Suspend().
http://joehacker.blogspot.com/2005/11/dont-use-threadsuspend-method.html

Ab.
http://joehacker.blogspot.com

Benny Raymond said:
I have a thread that sleeps for 5 minutes once it's finished running a
method and then it repeats itself if it's supposed to (bool = true).
Prior to 2.0 I was able to resume the thread after marking the bool to
false which would cause the thread to finish what it was doing and
complete, or to wake up for it's sleep state and not loop back into
itself anymore.

How do we tell a thread to stop sleeping now that Thread.Resume is
obsolete?
 
B

Benny Raymond

That's fine, however the thing you showed me is still sleeping - I need
to be able to wake up the sleeping thread, or terminate it (is that when
abort comes into play?)

Basically what I need to do is this:

* ClientA needs to be run every 5 minutes
* If SettingX changes to false, it allows ClientA to finish running
(if it's currently running) but it will no longer run again.
* If SettingX changes to true, it tells ClientA to start back up on
it's 5 minute cycle again.
* If App closes, it allows ClientA to finish running (if it's
currently running) but it will no longer run again.

What I was doing before (which I can see why it's wrong now but not how
to do it correctly):
* ClassX creates ClientA class
* ClassX sets loop_bool in ClientA to true
* ClassX starts ClientA thread
* ClientA thread runs and sleeps at the end
* When ClientA is done sleeping it loops, checks the loop_bool and
continus running if loop_bool is true.
* SettingX in ClassX changes
* ClassX sets loop_bool in ClientA to false
* ClassX Resumes ClientA thread
* ClassX Joins ClientA
* ClientA finishes and doesn't loop
* ClassX checks setting to see if it's true, if so it starts up the
ClientA thread again


Please help me.. haha :)

~Benny
 
J

Jon Skeet [C# MVP]

Benny said:
That's fine, however the thing you showed me is still sleeping - I need
to be able to wake up the sleeping thread, or terminate it (is that when
abort comes into play?)

You need to look through the example more carefully. The *producing*
thread is sleeping - the *consuming* thread is waiting.

The producing thread is only sleeping in order to simulate "things
happening" (processing, whatever). It's unimportant from the example's
point of view. Wait/Pulse is the important part here - you can give a
timeout to Wait, so that it will return either when the timeout has
elapsed or when the monitor is pulsed.

Jon
 
B

Benny Raymond

So what you're saying is that I should use Wait as if I was using Sleep
- and use Pulse to wake that Wait state up? That brings me to another
question however which is, how can I make sure that the thread is
Waiting before I pulse it, and how can I make sure the pulse gets there
in that circumstance? Hopefully this is clear if you look at the steps
I posted prior to your last message?
 
B

Benny Raymond

Nevermind, I looked back over it again with a clean head and it's only
waiting if nothing is in the queue, which means that if I pulse it after
adding to the queue things will be ok... So if you don't mind could you
look at this pseudo code for me?

class clientMonitor
{
myClient is a "client" from class client

function main
{
initialize myClient
if (run_client_global_setting is true) then myClient.Run
}

function updateClient (gets called in cases when
run_client_global_setting changes, or main form closes, etc)
{
if (run_client_global_setting is true) then
set myClient.keep_running to true
else
set myClient.keep_running to false

Lastly run the function client.Run
}
}

class client
{
locker is a readonly object
queue is a Queue
keep_running is a boolean

function Run (something)
{
Lock the listLock object
add object "something" to Queue stack
if queue's count == 1, pulse locker
Unlock listlock object
}

function client_runner
{
loop if keep_running is true
{
Run client function that takes a few seconds to complete, then...

Lock the listLock object
if the queue has no items in it, Wait on listlock until pulsed
or until 5 minutes is up
Unlock listlock object
}
}

}
 
B

Benny Raymond

is Monitor.Pulse actually like a enqueue and Monitor.Wait like a dequeue
except that if you give it a timeout it doesn't dequeue?
 
B

Benny Raymond

Ok... after some more messing around with it i've come up with this...
Do I still have the wrong idea?

Class A
{
// non related threading stuff....
// at some point
B _client = new B();
Thread _clientThread = null;
// end non related threading stuff...

public void RunMacro()
{
if (_prefrences.Enable)
{
StopMacro(); // stop just incase we're currently running.
_clientThread = new Thread(new ThreadStart(_client.ClientThead));
_clientThread.Name = "ClientThread " +
_clientThread.ManagedThreadId.ToString();
_clientThread.Start();
}
}

public void StopMacro()
{
try
{
if (_clientThread != null &&
_clientThread.ThreadState ==
System.Threading.ThreadState.Running)
{
// tell it not to run anymore
_client.KEEP_RUNNING = false;

// Add a pulse just to make sure it stops waiting
_client.PulseClient();

// join and let it finish running
_clientThread.Join();
}
}
catch (Exception) { }
}
}

Class B
{
// more code unrelated
// at some point:
public bool KEEP_RUNNING = false;
private readonly object locker = new object();
// end more code unrelated

public void PulseClient()
{
lock (locker)
{
Monitor.Pulse(locker);
}
}

public void ClientThead()
{
int i = 5 * 60 * 1000;
lock (locker)
{
while (KEEP_RUNNING)
{
if (_prefrences.Enable)
{
// RunClient will return 5min or 20min
i = RunClient();
}
Monitor.Wait(locker, i);
}
}
}

private int RunClient()
{
// do a bunch of stuff...
if ({some expression})
return 5 * 60 * 1000;
else
return 20 * 60 * 1000;
}
}
 
J

Jon Skeet [C# MVP]

Benny Raymond said:
is Monitor.Pulse actually like a enqueue and Monitor.Wait like a dequeue
except that if you give it a timeout it doesn't dequeue?

If anything, it's the other way round - you *could* think of
Monitor.Wait as adding a thread to a queue of threads to be pulsed,
although I don't believe the ordering of pulsing is guaranteed.

It's not a terribly helpful way of thinking about it though. Think of
it as a thread watching a reference to see when a light goes on (or
something like that). Pulse flashes that light.
 
B

Benny Raymond

The ordering of pulsing isn't guaranteed, but is the fact that a pulse
went out and hasn't been recieved yet guaranteed? Since I'm only using
two threads, one that waits and one that pulses wouldn't it be ok to
assume that every time I pulse, the wait block is going to hit it at
some point? The reason I ask this is that I need to pulse without
knowing where the client thread is, and if it's not waiting I don't want
it to wait once it gets to the waiting state (since i've already pulsed it).

Does that all make sense?

BTW: thanks a ton - app is already running a lot better.
 
J

Jon Skeet [C# MVP]

Benny said:
The ordering of pulsing isn't guaranteed, but is the fact that a pulse
went out and hasn't been recieved yet guaranteed? Since I'm only using
two threads, one that waits and one that pulses wouldn't it be ok to
assume that every time I pulse, the wait block is going to hit it at
some point? The reason I ask this is that I need to pulse without
knowing where the client thread is, and if it's not waiting I don't want
it to wait once it gets to the waiting state (since i've already pulsed it).

If you pulse when no thread is waiting, it's a no-op. That's the big
difference between a monitor and a semaphore. If you need that kind of
behaviour, you should look at ManualResetEvent and AutoResetEvent
instead.

Jon
 
B

Benny Raymond

I'm looking into AutoRaiseEvent and it seems like I only have to change
a couple lines of code - however when I give a timeout to the .WaitOne
it requires an exit context... What does it all mean?
"exitContext
true to exit the synchronization domain for the context before the wait
(if in a synchronized context), and reacquire it afterward; otherwise,
false.
"
 
J

Jon Skeet [C# MVP]

Benny Raymond said:
I'm looking into AutoRaiseEvent and it seems like I only have to change
a couple lines of code - however when I give a timeout to the .WaitOne
it requires an exit context... What does it all mean?
"exitContext
true to exit the synchronization domain for the context before the wait
(if in a synchronized context), and reacquire it afterward; otherwise,
false.
"

Unless you're using synchronization domains explicitly (and unless you
know you are, you aren't!) you can just pass in false.
 
B

Benny Raymond

Great... Ok, so this is what i'm doing now (one of the many places - i
went through today and fixed all of the areas where I was using threads
wrong). Let me know if I've finally got the right idea?


Class A
{
// stuff not needed...
// at some point _client is Class B
// On to the threading stuff:

public override void RunMacro()
{
if (_prefrences.Enable)
{
StopMacro(); // stop just incase we're currently running.

_client.KEEP_RUNNING = true;
_clientThread = new Thread(new ThreadStart(_client.ClientThead));
_clientThread.Name = "Taskulon5000 ClientThread " +
_clientThread.ManagedThreadId.ToString();
_clientThread.Start();
_client.SignalClient();
}
}

public override void StopMacro()
{
try
{
_client.KEEP_RUNNING = false; // tell it not to run anymore
if (_clientThread != null &&
(_clientThread.ThreadState == System.Threading.ThreadState.Running ||
_clientThread.ThreadState ==
System.Threading.ThreadState.WaitSleepJoin))
{
_client.SignalClient(); // Add a signal to make sure it stops waiting
_clientThread.Join(); // join and let it finish running
}
}
catch (Exception) { }
}
}


Class B
{
public volatile bool KEEP_RUNNING = false;
private AutoResetEvent autoEvent;
// other stuff...
// then..
public void SignalClient()
{
Debug.WriteLine("SignalClient");
autoEvent.Set();
}

public void ClientThead()
{
Debug.WriteLine("ClientThead");
int i = 5;
while (KEEP_RUNNING)
{
Debug.WriteLine(string.Format("Will wait {0} milliseconds", i),
"ClientThead");
bool a = autoEvent.WaitOne(i, false);
Debug.WriteLine(string.Format("Finished Waiting based on: {0}",
a ? "Signaled" : "Timeout"), "ClientThead");
if (_prefrences.Enable && KEEP_RUNNING)
{
i = RunClient();
}
else
{
KEEP_RUNNING = false;
}
}
}
}
 
J

Jon Skeet [C# MVP]

Benny Raymond said:
Great... Ok, so this is what i'm doing now (one of the many places - i
went through today and fixed all of the areas where I was using threads
wrong). Let me know if I've finally got the right idea?

<snip>

Sorry it's been so long.

1) I still wouldn't use the ThreadState to test whether it's running or
not. Just Join the thread - if it's finished, the call will just return
immediately, and signalling the client isn't going to cause any
problems.

2) I wouldn't have KEEP_RUNNING as a public field - I'd make it a
property. I'd also try to use the normal .NET naming conventions

3) Catching Exception and not doing anything with it is almost always a
bad idea - if something goes wrong, you won't have any record of it. At
the very least, log it somewhere.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top