|
devvvy wrote: Thread.Sleep is one-line of code, simple, and get the job done
Just because it's simple to implement, this doesn't mean it's a good choice. I recommend against Thread.Sleep precisely because of what it does - it suspends a thread for a timeout period. That doesn't seem too bad if you want to wait for a period, but the big problem comes when you want to terminate that thread. When a thread is sleeping, terminating it isn't easy - effectively, you have to wait for the thread to wake up just to kill it. This may not seem to be too big a deal, but if your system relies on having a number of these internally, you have just forced the user to wait and that's generally not a good thing.
The primary reason that I recommend against it is precisely because it's so easy to use. The problem is, people end up using it as a blunt object and force it into programs that it shouldn't be in, precisely because they don't understand the downsides. If you fully appreciate the tradeoffs in Thread.Sleep then, by all means, use it. Don't, however, put it into code that a noob is going to read - as they probably don't appreciate the underlying issues with Thread.Sleep then they will blindly use it.
There are other, subtle, problems with the use of Thread.Sleep, with relation to priority. A simple pattern, though, is simply to use Monitor.Enter to control the access, and this is my preferred choice in a lot of cases.
|
|
|
|
|
SCENARIO 1 - wait for task completion on another thread: I agree as I stated earlier not to use Thread.Sleep and that it's just outright wrong to do so.
SCENARIO 2 - humble timing while loop: I'm not hearing any reason not to use it. As indicated
* just because it's simple doesn't mean it's inappropriate
* the thread which host the while loop needs be created anyway so thread creation cost is irrelevant
* most applications don't need to know when *exactly* the blocked thread needs to *wake* up after specified period
* alternative is to use a timer+event/subscriber which does nothing more than complicate an otherwise cannot-be-simpler while loop with a Thread.Sleep
SCENARIO 3 Thread.Sleep(MagicDuration) or app breaks - well... this is a bug which demands correction in the first place.
I'm not hearing any new argument in support of not using Thread.Sleep in SCENARIO 2 -
- SCENARIO 1/3 is just plain stupid for anyone to use Thread.Sleep
- SCENARIO 2 not using simple Thread.Sleep is just waste of *my* time
This is an over discussed subject, gives people wrong impression this is actually complicated, that Thread.Sleep is really evil.
dev
|
|
|
|
|
Thread.Sleep() is not EVIL if you know how it works and if that's the behavior that you really want to accomplish. The reason people say it is evil because they use it wrongly without understanding how it works. devvvy wrote:
SCENARIO 2 - humble timing while loop: I'm not hearing any reason not to use it. As indicated If your application doesn't care about accuracy of the execution ineterval, then Thread.Sleep() is alright to use. Let us say you need to execute some task every minute and you start the application at 10AM. It is supposed to execute at 10.01, 10.02, 10.03 etc. You'd write something like,
while(!exit)
{
Thread.Sleep(10000);
} What happens if your job takes more than 1 minute? Then the next run which was supposed to happen at 10.01 won't happen. This delays the next execution too. With this design, it will be hard to tell when the next run will happen. If this behavior is alright for your application, there is no problem in using Thread.Sleep() . To workaround this problem, you can use System.Threading.Timer to schedule the job. It gives a better scheduling capabilities and executes the job exactly at the interval that you specify. Timer callback method can be executed simultaneously by multiple threads if the job takes more time than the interval. This increases parallelism and makes the processing faster.
It is also logical to think that why do you need to waste a thread by just sleeping? The wastage could be minimal, but it is a wastage. Where System.Threading.Timer uses thread pool threads and thread pools are more optimized for better usage of resources. Thread pools are initialized with a set of threads when the application domain starts. devvvy wrote:
This is an over discussed subject, gives people wrong impression this is actually complicated, that Thread.Sleep is really evil. It's about maturity. If you know how Thread.Sleep() works then you'd probably use it correctly and use alternatives where Thread.Sleep() is not the right solution. Any statement which says Thread.Sleep() is evil without understanding the context where it is used is STUPID.
Best wishes,
Navaneeth
modified 18-Feb-13 23:36pm.
|
|
|
|
|
To overthrow the uneducated accusation on Thread.Sleep from self righteous syntax high priests
(but i pointed out very beginning timer/handler as alternative + exactly when next loop gets executed is un-important for 99% of the apps)
dev
|
|
|
|
|
In scenario 2, you're confusing the need to create the thread with the need to use it as a timer. If you need to use something as a timer, then why not use a timer? However, this case is the one that is potentially the most dangerous. Suppose that your application creates 10 threads and then puts them to sleep for 30 seconds, and each thread has opened up some resources that must be disposed of when the thread completes. Now, suppose that 2 seconds into this, your application wants to close - what do you think the effect will be?
The reason that it's so discussed is that it does have drawbacks, and it can be inherently risky. It's very simplicity is what makes it so attractive, and it can end up being used when it is inappropriate to do so because you don't appreciate the subtleties involved in using it. Threading and multi-tasking is not an easy thing to get right, it really isn't. As I said earlier, using it when you know exactly what goes on with it is fine, it's when you don't understand the drawbacks that it's a problem. And using something because it's slightly less typing than the alternatives is just lazy programming - don't use something because it saves you a few keystrokes, use the tool that is right and appropriate.
|
|
|
|
|
Pete O'Hanlon wrote: then why not use a timer?
because there's no reason to - as 99% of app don't need to know exactly when next while loop get executed, so why complicate things which are otherwise simpler? it's as *dangerous* as not knowing exactly when next loop get executed which 99% of applications don't care/matter
Pete O'Hanlon wrote: it's so discussed is that it does have drawbacks, and it can be inherently risky. I
Using Thread.Sleep for SCENARIO 1/3 is just plain wrong. This complicates the otherwise simple discussion. Things which are simple should remain simple.
Pete O'Hanlon wrote: don't use something because it saves you a few keystrokes, use the tool that is right and appropriate.
But I was just contemplating using your suggestion wrapping timer into a single line function. As I do agree - after you wrap it to single line,
a. it's as simple as thread.sleep
b. now you know exactly when next execution happens
Pete O'Hanlon wrote: Suppose that your application creates 10 threads and then puts them to sleep for 30 seconds, and each thread has opened up some resources that must be disposed of when the thread completes. Now, suppose that 2 seconds into this, your application wants to close - what do you think the effect will be?
This is a Thread.Abort or App Exit clean up issue, not Thread.Sleep issue - it's always bad to forcefully terminate app/threads. I take what you mean as following?
<br />
try {<br />
while(true) {<br />
using(Stream...)<br />
{<br />
... <br />
Thread.Sleep(#1) <-- What would happen? indeterministic<br />
} <-- Dispose here anyway as "using" translated to try-finally (But what if aborted during finally)<br />
<br />
Thread.Sleep(#2) <-- fine already disposed<br />
}<br />
catch(ThreadAbortEx)<br />
{<br />
<br />
}<br />
finally{<br />
<br />
}<br />
dev
|
|
|
|
|
This isn't meant as a sarcastic reply but one of learning.
What would you recommend as a better method of doing the same as thread.sleep inside a thread?
Lobster Thermidor aux crevettes with a Mornay sauce, served in a Provençale manner with shallots and aubergines, garnished with truffle pate, brandy and a fried egg on top and Spam - Monty Python Spam Sketch
|
|
|
|
|
Simon_Whale wrote: What would you recommend as a better method of doing the same as thread.sleep inside a thread? If you want to run a job which executes in every 'n' minutes, you can use System.Threading.Timer .
If you want to wait till another thread finishes execution, you can use WaitHandle.
If you just want to sleep, use Thread.Sleep()
Best wishes,
Navaneeth
|
|
|
|
|
sure as i pointed out earlier timer/event subscriber - but why bother.
THUS FAR there isn't ONE SINGLE argument that justify against use of Thread.Sleep against SCENARIO 2.
I hereby invite you synatex lawyers/bitches to put forth your challenge to overthrow this hypothesis.
dev
|
|
|
|
|
devvvy wrote: THUS FAR there isn't ONE SINGLE argument that justify against use of
Thread.Sleep against SCENARIO 2.
Errm. Yes, we have posted arguments against, you're just choosing to ignore them.
As for the reason I show Monitor.Wait is that it is close to the behaviour you're after with your Thread.Sleep, in that it puts the ThreadState into WaitSleepJoin, but it doesn't yield the thread to the OS. This is an important point because you can wake this thread up if you need to. This is the point you seem to be missing. Thread.Sleep - there is no wake up, other than through a Thread.Abort and we've already covered how that makes things unpredicable - if you need to cancel the thread and have it tidy itself up you have to wait for it to wake up.
Also, Dave has a very valid point about the behaviour in STA COM. In this scenario, again, this is a justification that Thread.Sleep should not be used. It is not the appropriate mechanism.
|
|
|
|
|
Pete O'Hanlon wrote:
Errm. Yes, we have posted arguments against, you're just choosing to ignore them. I second that.
He don't have the maturity to understand what people are saying. So no point in discussing further.
|
|
|
|
|
there's no point because you're still confused SCENARIO 2 a simple background thread with a while+Sleep with no UI pump, with SCENARIO 1/3
you ran out of further arguments don't you?
dev
|
|
|
|
|
1. As I pointed out earlier, there's no need to know *exact* when the blocked thread wakes up again.
2. STA COM debug messages -> how's debug messages in debug mode in a thread with a message pump affect me if all i've got is a non-ui baclground thread?
dev
|
|
|
|
|
devvvy wrote: 1. As I pointed out earlier, there's no need to know *exact* when the blocked thread wakes up again.
There is if you're trying to shut down an application. I don't know how many times I can point out the same thing; perhaps with a simple example - you have a service with a thread that needs to clean up before the service can shut down - by having to wait for the thread to finish, you could trigger the "Service could not be stopped, blah blah blah" message. I have seen this happen many times, and it's always been because someone who doesn't know any better has decided that a simple one liner is better then something that behaves cleanly.
If you know what you're doing, and if you're well informed about the pitfalls in Thread.Sleep, and if you've thought through the implications then by all means, use Thread.Sleep. If you can't claim all of these conditions, then look for a safer alternative - one that won't leave your users wanting to hang you by your testicles when you inconvenience them because you couldn't be bothered to type in three lines.
|
|
|
|
|
Pete O'Hanlon wrote: There is if you're trying to shut down an application. I don't know how many times I can point out the same thing; perhaps with a simple example - you have a service with a thread that needs to clean up before the service can shut down - by having to wait for the thread to finish, you could trigger the "Service could not be stopped, blah blah blah" message.
My apologies Pete - this is something we'd run into if we're not careful with SCENARIO 2 if Thread.Sleep(LONGTIME) (where timer/handler would have avoided this). Having consider this, Thread.Sleep even for SCENARIO 2 may likely to cause problem in app exit if not used carefully. I don't think this very important argument has nearly enough visibility in this discussion/other places. Thanks Pete!
Thread.Sleep is Evil after all. (For SCENARIO 1,2,3)
Sample to demo the issue as follows:
<br />
static void Main(string[] args)<br />
{<br />
Thread t = new Thread(new ThreadStart(ThreadFunc));<br />
t.Start();<br />
<br />
Console.WriteLine("Hit any key to exit.");<br />
Console.ReadLine();<br />
<br />
Console.WriteLine("App exiting");<br />
return;<br />
}<br />
<br />
static void ThreadFunc()<br />
{<br />
int i=0;<br />
try<br />
{<br />
while (true)<br />
{<br />
Console.WriteLine(i);<br />
Thread.Sleep(1000 * 10);<br />
i++;<br />
}<br />
}<br />
finally<br />
{<br />
Console.WriteLine("Exiting while loop");<br />
}<br />
return;<br />
dev
|
|
|
|
|
devvvy wrote:
THUS FAR there isn't ONE SINGLE argument that justify against use of Thread.Sleep against SCENARIO 2. As Pete already told, you are ignoring the comments that we made for Scenario2. See my answer.
|
|
|
|
|
i pointed out timer + event handler as an alternative in the first place, but it's more lines of code for no additional benefit than a simple while+Sleep
dev
|
|
|
|
|
I haven't read the article at all, but I'll give you another reason why it's evil. Every once in a while, you can get this little cryptic error message and you've got absolutely no clue as to what it means or why you're getting it:
"The CLR has been unable to transition from COM context #x###### to COM context #x###### for 60 seconds. The thread that owns the destination context/apartment...blah blah blah"
Why does this happen?? Well, you get this mesage onyl when running under the debugger. Usually it's because Thread.Sleep has been called for greater than 60 seconds or there is a long running operation going on on a thread hosting a message pump. STA COM is accomplished through message passing and if those message don't get processed ... kaboom!
|
|
|
|
|
ok, that's if the worker thread has a message pump - if not nothing wrong.
dev
|
|
|
|
|
No, it's not. Do you know how times I've seen Thread.Sleep show up on the UI thread?? LOTS!
|
|
|
|
|
still - there's nothing against SCENARIO 2, if it's not a UI thread or one with a message pump.
Thread.Sleep isn't evil - it's just uncool. It's uncool because most developers tell each other it's uncool to do so.
dev
|
|
|
|
|
OK, it's "uncool" because most people (noobs) use it like they use PictureBox. They use it without knowing it's limitations and without knowing that there are far better alternatives to it.
|
|
|
|
|
it's a simple reliable picture box. if people use it for SCENARIO 1/3 it's just absurb in the first place.
but SCENARIO 2 it's just not much to talk about - the fact there is simply because people wasting each other time trying to complicate otherwise very simple Thread.Sleep
dev
|
|
|
|
|
Oh but Thread.Sleep is not so simple. Using it has vast implications on the functionality of the rest of your app. That's why so many noobs use it and can't figure out why their app doesn't work properly or, as you mentioned, you can't shutdown a service without timing out the Service Manager.
|
|
|
|
|
I saw two arguments against using Thread.Sleep for scenario 2
a. From you: Thread.Sleep screw up message pump IF you do this on UI Thread (But why'd you Thread.Sleep on UI in the first place!)
b. From Pete: Application exit
Both are valid arguments - But I don't think I stumble across these in other places at all. They deserve more visibility I now agree - Thread.Sleep is evil.
(And can be replaced/avoided by one line timer+handler if you wrap it up in one blocking function call)
Thank you!
dev
modified 19-Feb-13 20:29pm.
|
|
|
|