.NET Forum / Languages / C# / October 2007
Break thread sleep
|
|
Thread rating:  |
suga.masanobu@gmail.com - 03 Oct 2007 11:22 GMT Hello group.
I have thread in which I perform specific task in loop. I can specify, by check box, in what periods of time that task should be done, ex. instantly, with 5min break, with 15min break etc. For now I had it done in way like that.
while(true) { period = checkIfPeriodChanged(); ... performTask ... Sleep(period); }
That works fine, until I want to change period time. For example, when I set period to 15min, and after performTask I change it again to 1min, I have to wait all ~15min, to put my new settings (1min) into operation. Is there any way, to break Sleep(period), or should I do it in very different way? I looked at System.Threading.Timer, but i'm not sure if it'll be working, becouse I don't know how long time execute performTask will take (differences can be rather wide - from couple seconds to few minutes).
I will be gratefull for any kind of help. Masanobu Suga
Jon Skeet [C# MVP] - 03 Oct 2007 11:28 GMT On Oct 3, 11:22 am, suga.masan...@gmail.com wrote:
<snip>
> That works fine, until I want to change period time. For example, when > I set period to 15min, and after performTask I change it again to > 1min, I have to wait all ~15min, to put my new settings (1min) into > operation. Is there any way, to break Sleep(period), or should I do it > in very different way? Instead of using Thread.Sleep, use Monitor.Wait, "breaking" it with Monitor.Pulse.
Jon
suga.masanobu@gmail.com - 05 Oct 2007 14:36 GMT > Instead of using Thread.Sleep, use Monitor.Wait, "breaking" it with > Monitor.Pulse. That's first class solution but I still have some problems. If I put Monitor.Wait in loop and break it with Monitor.Pulse putted in event (radio button click) I won't have continuity - after one iteration loop will wait for pulse which is only in click event, so only if I'll click radio button loop will coutinue (only one iteration again). I thought about adding aditional pulse to other event, like 'add to list', but I'm not sure yet, if it'll be working good. If that's not good idea, and I'm still not using Monitor.Wait/Pulse in a good way, please correct me.
Jon Skeet [C# MVP] - 05 Oct 2007 15:40 GMT On Oct 5, 2:36 pm, suga.masan...@gmail.com wrote:
> > Instead of using Thread.Sleep, use Monitor.Wait, "breaking" it with > > Monitor.Pulse. [quoted text clipped - 8 lines] > good idea, and I'm still not using Monitor.Wait/Pulse in a good way, > please correct me. It's not clear to me what the problem is, I'm afraid. Could you post a short but complete program that demonstrates the issue? See http://pobox.com/~skeet/csharp/complete.html
Jon
Willy Denoyette [MVP] - 03 Oct 2007 11:41 GMT > Hello group. > [quoted text clipped - 23 lines] > I will be gratefull for any kind of help. > Masanobu Suga I suppose *performTask* starts another thread to run the task, why not simply use Thread.Join instead of Sleep?
Willy.
suga.masanobu@gmail.com - 05 Oct 2007 14:42 GMT On 3 Pa , 12:41, "Willy Denoyette [MVP]" <willy.denoye...@telenet.be> wrote:
> I suppose *performTask* starts another thread to run the task It's not. performTask is using specific method from 'add reference' library. I'm not sure if I really need to make separate thread for it. (And tell you the truth I don't even know how. That perforTask takes some arguments, and while running it's sending/returning some information to form).
Willy Denoyette [MVP] - 05 Oct 2007 17:02 GMT > On 3 Pa , 12:41, "Willy Denoyette [MVP]" <willy.denoye...@telenet.be> > wrote: [quoted text clipped - 5 lines] > some arguments, and while running it's sending/returning some > information to form). Well it looks like you are calling a method, that in turn calls you back to update the form. If the above is correct, then I need some more info: 1. What kind of library is this, this is, what are you adding with "add reference"? 2. On what thread are you calling this "performTask", is it on the UI thread (I hope it's not) or on another thread (I guess it's not) ?
Willy.
Peter Duniho - 03 Oct 2007 17:48 GMT > [...] > while(true) [quoted text clipped - 11 lines] > operation. Is there any way, to break Sleep(period), or should I do it > in very different way? A couple of suggestions:
1) If you want to block with a timeout but still be alertable, you can use a WaitHandle (eg AutoResetEvent) and call WaitOne() with a timeout (eg "period"). This is similar to the Monitor method Jon mentions; it's just a different way of doing the same thing (assuming you use the Monitor.Wait() overload with a timeout).
2) IMHO, if the goal is to run a specific task at specific intervals, and you want the user to be able to modify the interval, your current implementation isn't really the best anyway.
I think it would be better to just use the Forms.Timer class to have an event raised on a specific time interval, and then use a BackgroundWorker or similar to run the task. Rather than having a thread sitting around waiting to see if the time period changes or expires, instead you would simply have the UI update the timer period in response to user actions, and in the event raised by the timer object assign a thread (via BackgroundWorker or similar) to actually do the task.
Pete
suga.masanobu@gmail.com - 05 Oct 2007 14:54 GMT > IMHO, if the goal is to run a specific task at specific > intervals, and you want the user to be able to modify the interval, your > current implementation isn't really the best anyway. Your suggestions are really nice BUT... (always that but ;-) ). The trick is that I don't know how long time would single loop takes. So I don't know when use Timer to raise task, after I did it once. Perhaps in longer periods (like 15min) it won't be a problem, as task won't take so long to perform, but if I set that it should be performed without brakes (task, 0 sec break, task, 0 sec break etc.) I think Timer won't work, as it don't know how long time task will take (how long it should wait). Generally my break before performing tasks is performTaskTime + userDefinedBreakTime.
Peter Duniho - 05 Oct 2007 19:37 GMT >> IMHO, if the goal is to run a specific task at specific >> intervals, and you want the user to be able to modify the interval, your >> current implementation isn't really the best anyway. > > Your suggestions are really nice BUT... (always that but ;-) ). > The trick is that I don't know how long time would single loop takes. Not really a problem at all. You just need to decide what you want to do about it.
> So I don't know when use Timer to raise task, after I did it once. If you have a requirement to not start a new task while the current one is executing, then you need to decide how exactly you want to handle that case. There are at least two behavior choices:
1) You want the task to be run on specific intervals, and if it's already running when an interval has expired, just wait for the next interval to try again.
2) You want the task to be run no more frequently than a specific interval, but if an interval expires while the task is still being performed, you want the next iteration of that task to happen immediately when the current one has completed.
Both options are easily implemented. In the first scenario, you would simply maintain a volatile flag indicating whether the task is currently running or not. You'd set the flag when starting the task, and clear it when the task completes. Then you just look at the flag before starting the task, and don't bother starting it if it's already set.
In the second scenario, the easiest solution IMHO would be to use a WaitHandle. You'd have a regular thread (not BackgroundWorker) that just sits in a loop waiting on the WaitHandle, and doing the processing when the handle is set (I'd use an AutoResetEvent for convenience). Then each time the timer interval expires, you simply set the WaitHandle. If the task is already ongoing, this will ensure that the next time it waits on the WaitHandle, it simply continues rather than actually blocking. If the task isn't already ongoing, then the thread will be waiting on the WaitHandle and setting it will release the thread so that it can do the processing you want.
I think one of those two behaviors are most likely to fit your needs. But if not, you simply need to think about what behavior _would_ fit your needs and then implement it.
> Perhaps in longer periods (like 15min) it won't be a problem, as task > won't take so long to perform, but if I set that it should be > performed without brakes (task, 0 sec break, task, 0 sec break etc.) I > think Timer won't work, as it don't know how long time task will take > (how long it should wait). Generally my break before performing tasks > is performTaskTime + userDefinedBreakTime. Just to clarify: the way I read that last sentence is that the interval between initiation of the performance of your task is variable, and depends on the user-defined time _and_ the actual time it took to perform the task.
For example, assuming the user has asked for 10 second intervals, but the task performance time is variable, you might have a sequence that looks like this:
Time Activity ----- ------------ 0 s perform task, 3 seconds 3 s wait 10 seconds 13 s perform task, 2 seconds 15 s wait 10 seconds 25 s perform task, 8 seconds 33 s wait 10 seconds
etc.
If that's the case, I really don't see what the problem is. That's a trivial behavior to implement. I think all of us assumed that you wanted some timing independent of the length of time it takes to actually perform the task, and our answers have been directed to that goal.
If the answers haven't explained the issue to you well enough yet, it seems to me you need to consider trying to rephrase your original question so that it is much more clear about what you actually want to accomplish.
Pete
suga.masanobu@gmail.com - 11 Oct 2007 07:45 GMT > 1) You want the task to be run on specific intervals, and if it's > already running when an interval has expired, just wait for the next [quoted text clipped - 4 lines] > performed, you want the next iteration of that task to happen > immediately when the current one has completed. These two solutions are really good and simple in theory, and I'm little bit embrassed I didn't think about it in that way.
> In the second scenario, the easiest solution IMHO would be to use a > WaitHandle. You'd have a regular thread (not BackgroundWorker) that [quoted text clipped - 6 lines] > will be waiting on the WaitHandle and setting it will release the thread > so that it can do the processing you want. That is solution which nicely fit to my problem, and should solve it in a good, simple way. I'll do it and report if I find any problems.
Thank you very much for your help.
Peter Duniho - 12 Oct 2007 01:17 GMT >> In the second scenario, the easiest solution IMHO would be to use a >> WaitHandle. [...] > > That is solution which nicely fit to my problem, and should solve it > in a good, simple way. I'll do it and report if I find any problems. A caveat, one that I only just learned about.
The .NET documentation says that if you use any of the WaitHandle-derived classes, that the thread that waits on the object must use the Thread.BeginThreadAffinity() method to ensure that the managed thread stays with a given OS thread.
Why this behavior isn't automatically implemented in the WaitHandle-derived classes, I'm not sure. Also, it remains unclear to me whether managed threads can, in the current implementation of .NET, be run on multiple OS threads. In theory there's no reason that couldn't happen, but I've never seen anything definitive that says that's how it works.
So, sometime before you call WaitHandle.WaitOne(), you need to call Thread.BeginThreadAffinity() and some time after you return from WaitHandle.WaitOne(), you need to call Thread.EndThreadAffinity(). It's possible you'd just want to call those at the entry and exit point of your thread, with the entire thread always being tied to a given OS thread.
Pete
Jon Skeet [C# MVP] - 12 Oct 2007 07:47 GMT > > That is solution which nicely fit to my problem, and should solve it > > in a good, simple way. I'll do it and report if I find any problems. [quoted text clipped - 18 lines] > possible you'd just want to call those at the entry and exit point of > your thread, with the entire thread always being tied to a given OS thread. Where's the documentation that states that? I can't see it in the WaitHandle docs, and the examples don't include it.
I'm *hoping* that you've misunderstood a statement somewhere...
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too
Peter Duniho - 12 Oct 2007 08:27 GMT > Where's the documentation that states that? I can't see it in the > WaitHandle docs, and the examples don't include it. > > I'm *hoping* that you've misunderstood a statement somewhere... I don't think I did.
It's in one of the dumber places possible, IMHO. Rather than being in a place where someone who is doing the thing that imposes the requirement might see it, it's in a place where someone who already is aware of the requirement would see it:
http://msdn2.microsoft.com/en-us/library/system.threading.thread.beginthreadaffi nity.aspx
In particular:
For example, if your application calls a system API to acquire an operating system lock that has thread affinity, such as a Win32 CRITICAL_SECTION, you must call BeginThreadAffinity before acquiring the lock, and EndThreadAffinity after releasing the lock.
You must also call BeginThreadAffinity before blocking on any .NET Framework type that inherits from WaitHandle, because these types depend on operating system objects.
This remark says that this requirement exists only on "some hosts of the CLR", and calls out specifically SQL Server "Yukon". However, given the admonishments I've seen about not generally assuming that a managed thread is the same as an OS thread, I would say that unless you know for sure your code is NOT going to run in such an environment (and who knows what versions of .NET will introduce that behavior later?), it's better to be safe than sorry.
Pete
Jon Skeet [C# MVP] - 12 Oct 2007 10:06 GMT <snip>
(Thanks for the reference)
> This remark says that this requirement exists only on "some hosts of the > CLR", and calls out specifically SQL Server "Yukon". However, given the [quoted text clipped - 3 lines] > what versions of .NET will introduce that behavior later?), it's better > to be safe than sorry. Hmm. I think it also depends on what it means by "before blocking on".
I'll mail Joe Duffy tonight and see what he thinks.
Jon
Peter Duniho - 12 Oct 2007 18:02 GMT > Hmm. I think it also depends on what it means by "before blocking on". > > I'll mail Joe Duffy tonight and see what he thinks. Well, wouldn't WaitHandle.WaitOne() be considered "blocking on"?
I'm not really sure how "before blocking on" is ambiguous. It seems pretty clear to me. What's the ambiguity?
That said, I hope Willy's reply is correct and that this is just an out-of-date bit of documentation. I would expect any .NET Framework type that has this dependency to deal with it on its own (and already said so :) ), as Willy says that Mutex does.
Pete
Willy Denoyette [MVP] - 12 Oct 2007 10:22 GMT >> Where's the documentation that states that? I can't see it in the >> WaitHandle docs, and the examples don't include it. [quoted text clipped - 31 lines] > > Pete Above is only partly correct, it seems like this is somewhat outdated too (note Yukon, while the official name is since long SQL2005). It's true that when running managed code in an hosted environment like SQL Server (2005 and up) that you may need to take care about thread affinitized OS objects like Critical sections, but it's not true that you need to call BeginThreadAffinity/EndThreadAffinity before blocking on a WaitHandle derived Framework type. The only type that derives from WaitHandle in the Framework that has thread affinity is the Mutex, and this issue is taken care of by the Mutex class itself (Just like the CLR takes care of that for Monitor and ReaderWriterLock). Sure, if you implement your own WaitHandle derived types or *locks*, based on thread affinitized OS object handles or Critical Sections, then you need to make sure you don't move to another thread.
Willy.
Peter Duniho - 12 Oct 2007 18:06 GMT > [...] Sure, if you implement your own WaitHandle derived types or *locks*, > based on thread affinitized OS object handles or Critical Sections, then > you need to make sure you don't move to another thread. Well, the docs are clearly not talking about user-defined types. It specifically calls out "any .NET Framework type".
I do hope you're correct that the docs are just plain wrong. It seems like a silly requirement to me. But it _is_ in the docs; it would be nice to know for sure what the truth is.
Pete
Jon Skeet [C# MVP] - 12 Oct 2007 18:25 GMT > > [...] Sure, if you implement your own WaitHandle derived types or *locks*, > > based on thread affinitized OS object handles or Critical Sections, then [quoted text clipped - 6 lines] > like a silly requirement to me. But it _is_ in the docs; it would be > nice to know for sure what the truth is. I'll still mail Joe Duffy. He's usually fabulous about clearing up this kind of thing :)
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too
Peter Duniho - 12 Oct 2007 19:48 GMT > [...] >> I do hope you're correct that the docs are just plain wrong. It seems [quoted text clipped - 3 lines] > I'll still mail Joe Duffy. He's usually fabulous about clearing up this > kind of thing :) That would be great. I'd also like to see a single, definitive statement regarding what assumptions one can make, if any, regarding the relationship between a managed thread and an unmanaged thread.
I can see the advantage in having them be separate concepts, but it seems to me that if this is going to be the case, the framework should hide those implementation details from us. The framework should be making things _simpler_, not more complicated.
Pete
Willy Denoyette [MVP] - 12 Oct 2007 19:23 GMT >> [...] Sure, if you implement your own WaitHandle derived types or >> *locks*, based on thread affinitized OS object handles or Critical [quoted text clipped - 8 lines] > > Pete IMO the docs are wrong, the latest MSDN docs (VS2008 MSDN) have this sentence removed, and Yukon is now SQL2005 (which will confuse people when SQL2008 hits the streets). These API's where added late in the Whidbey cycle, a lot of changes were necessary because of the removal of fiber support in the CLR , support which was entirely moved to the SQL2005 (Yukon) host.
Another reason why I believe they are wrong is found in the Mutex class (mutants have thread affinity), it calls BeginThreadAffinity on your behalf when the Mutex gets created and BeginThreadAffinity when the Mutex gets Released. Note that these internal calls result in a NOP when the CLR is not hosted in a process that doesn't care about managing his own threads, the CLR doesn't do anything significant when you call this API in a non hosted environment. All other WaitHandle derived types do not wrap thread affinitized OS objects.
Willy.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|