0

So after some heavy research into multi-threading and how to handle thread completion I have come across several solutions. Some solutions seem a lot more useful and informative than others. I would like to take some time to explain what I already know, and then in return, I would like to better understand why these solutions are implemented so variously. The original topic of this post was to discover the difference between Thread.Sleep(x) and do {} while (b);. From my understanding these two solutions are only different in the sense that Thread.Sleep(x) will use less CPU than the latter. Spin waiting (empty while loop) will essentially run continiously from the CPU spiking percentages upwards of 85% which is a bad thing even on the fastest computers, I could only imagine what this would do to the average home computer.

Thread.Sleep

MSDN clearly states that when using Thread.Sleep(x) the thread does not execute during the time specified.

The thread will not be scheduled for execution by the operating system for the amount of time specified.

There are other options recommended within the remarks section of Thread.Sleep(x) such as using Timeout.Infinite or Mutex, Monitor, Semaphore, etc to synchronize threads and manage resources in a better manner. What is your opinion on this? Wouldn't this be just as bad as freezing the GUI with spin waiting?

MSDN also states that the since the system clock ticks at a specific rate called the clock resolution, the actual timing may not be the exact value specified since it is adjusted to coincide with clock ticks.

Spin Waiting

From my understanding this is an entirely bad practice. Once you initiate an empty loop it essentially blocks the thread it is executing it. This can result in freezing, crashing, and unresponsive GUIs, not to mention this can slow the user's computer down signifigantly since neither the compiler nor the operating system understand that the loop can be optimized to save uneccesary hits on performance. From my reading, the average computer can have between one and two cores of it's CPU running at 100% simply due to an empty while loop being executed continuously. The only effective usage of Spin Waiting that I've read about is thread synchronization. Have you used this to synchronize threads? I would imagine that there are better solutions and that using an empty loop would be problematic for debugging as well.

Background Worker

The BackgroundWorker object has an event called RunWorkerCompleted that is raised when the DoWork event handler returns. In my experience with threading (which is minimal) I have always used this event to execute code once the threaded operation has completed. The biggest thing to take into account with this event is that if the background thread was canceled then you have no true way of knowing since the Canceled flag will not be set to true if the CancellationPending flag has been set to true and missed by the polling loop. MSDN states it more thoroughly:

Be aware that your code in the DoWork event handler may finish its work as a cancellation request is being made, and your polling loop may miss CancellationPending being set to true. In this case, the Cancelled flag of System.ComponentModel.RunWorkerCompletedEventArgs in your RunWorkerCompleted event handler will not be set to true, even though a cancellation request was made. This situation is called a race condition and is a common concern in multithreaded programming. For more information about multithreading design issues, see Managed Threading Best Practices.

Final Thoughts

Since there are many ways to accomplish multiple tasks at the same time, which is generally considered best practice, why is it best practice, and what are the biggest differences between them all? I've put a lot of thought into this, and am highly curious about the advice of developers with more experience.

NOTES

I have dove deep into Google, MSDN, StackOverflow, and Daniweb, to put a good research effort into this question. The final thoughts area is the primary question set I would like to have answered. I believe the original post here was too broad and needed further information and clarity before I could recieve the answer I was truly looking for, and I apologize for taking so long to clarify my question.

Thank you all for your input!

-Jamie

DUPLICATE DIFFERENCE

In this post marked as duplicate to this one, the OP is requesting information on how to solve a problem with their BackgroundWorker object not actually raising the RunWorkerCompleted event, I am not having this issue, nor is my posting requesting information about this issue. My post is requesting detailed information on the difference between the three most common methods of waiting on a thread to complete before executing final operations. My main concern is the advantage and disadvantage to each solution as well as any further solutions that are considered common or best practice with multi-threading.

  • 3
    Because a do nothing loop is doing something, calling `IsBusy` over and over and over and over..... and basically pegs the CPU – juharr Sep 26 '17 at 15:45
  • 1
    The usual reason for the sleep is that without it you get a tight loop that spikes your CPU to 100%. Both methods are pretty awful though and there's usually a better option (event driven programming or callbacks for example) – DavidG Sep 26 '17 at 15:45
  • That is understandable, but isn't the while loop involving `Thread.Sleep(x)` essentially doing the same thing but at a slower rate? –  Sep 26 '17 at 15:46
  • 2
    With an idle loop, you'll find your process burns up a lot of resources repeatedly re-evaluating the loop (as frequently as it can manage). When you Thread.Sleep() you signal to the OS not to perform any work with this thread for however long. There are perhaps "better" ways to achieve this, but a Thread.Sleep() loop balancing performance/reactivity is a very common thing to see. Note that the OS has "very clever"™ ways of scheduling work on the CPU - so it does not translate Thread.Sleep() into an idle loop. It can manage the CPU resource better. –  Sep 26 '17 at 15:46
  • 2
    `I frequently see the following snippet of code` Then you need to fix that, because that's a *really* bad thing to see. `Thread.Sleep(x) are used frequently` Again, you need to fix that. – Servy Sep 26 '17 at 15:47
  • @DavidG what would be some better alternatives? Just some brief supporting overviews since the explanation as to why these things are bad in their own ways and the difference between them is the primary focus of my question. –  Sep 26 '17 at 15:48
  • Thread.Sleep will cause the current thread to yield allowing another thread to execute. bw.IsBusy will never end in a single processor environment as the other thread (that sets bw.IsBusty to false on completion I assume) would never get any processing time. See https://stackoverflow.com/questions/9417260/when-is-it-sensible-to-use-thread-sleep – Kell Sep 26 '17 at 15:49
  • @lxxtacoxxl Start with the documentation for BGW. It has lots of information on how to use it properly in lots of different situations, including yours of how to run code when it's done. – Servy Sep 26 '17 at 15:49
  • It's worth pointing out that it's also something to do in a single threaded application, e.g., a Windows Service where the program needs to sit idle before periodically checking something. This can also be achieved using a `Timer` object; https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx – DiskJunky Sep 26 '17 at 15:49
  • @Ixxtacoxxl please see here for alternatives to Thread.Sleep() - i.e. recommendations for what to use instead. https://stackoverflow.com/questions/5424667/alternatives-to-thread-sleep –  Sep 26 '17 at 15:49
  • write a pair of small apps that do both methods - you dont need multiple thread just the waiting thread, now look at the CPU consumption – pm100 Sep 26 '17 at 15:49
  • @Servy I am completely agreeing as I'm reading these comments that this is a very bad idea either way you go, however, I see these examples all over StackOverflow, Daniweb, MSDN Dev Forums, and more. –  Sep 26 '17 at 15:50
  • @lxxtacoxxl If you know it's a bad idea, then why are you doing it? Yes, lots of people suggest doing bad things on the internet, you need to be suspicious of the information you read for exactly that reason. – Servy Sep 26 '17 at 15:51
  • @Servy In relation to documentation of BGW, I currently use the built in event to handle my completion code per the documentation. I know there are other ways, but essentially this post was to discover the true differences with supporting evidence as to how the two ideas are different. I believe this has been done solely through comments, but would love a descriptive answer to give credit for a well written response. –  Sep 26 '17 at 15:53
  • You could look into TPL and Async as (more elegant and efficiënt) alternatives to BGW & Threads for concurrent/asynchronuous programming. – Johan Donne Sep 26 '17 at 15:57
  • 1
    The reason you see these examples everywhere is because they are the simplest to demonstrate. StackOverflow solutions are generally meant to be coded in the simplest way, without regard to anything but the question. As far as C# goes, it's almost always a better design decision to use Async/Await or some other way to avoid busy-waits, but rarely do design questions fit the scope of a SO topic. – Clay07g Sep 26 '17 at 16:24
  • Dreadful practice, the more this is found the more programmers get this wrong. I'm going to hammer this. – Hans Passant Sep 26 '17 at 16:32
  • @HansPassant I am by no means wanting to spread bad practice, hence the reason for my questioning. I have revised the question to be more thorough and to retrieve a more detailed collection of actual answers instead of comments. I'm pretty sure I won't be the only developer to ever think into this topic. –  Sep 26 '17 at 17:25

0 Answers0