C# Cannot join main thread - c#

I have very simple code which behavior I cannot understand.
class Program
{
static void Main(string[] args)
{
// Get reference to main thread
Thread mainThread = Thread.CurrentThread;
// Start second thread
new Thread(() =>
{
Console.WriteLine("Working...");
Thread.Sleep(1000);
Console.WriteLine("Work finished. Waiting for main thread to end...");
mainThread.Join(); // Obviously this join cannot pass
Console.WriteLine("This message never prints. Why???");
}).Start();
Thread.Sleep(300);
Console.WriteLine("Main thread ended");
}
}
Output of this never-ending program is:
Working...
Main thread ended
Work finished. Waiting for main thread to end...
Why the threads' code get stuck on the Join() method call? By other print outs can be find out, that already before Join() call, the propertyIsAlive of mainThread is set to false and the ThreadState is Background, Stopped, WaitSleepJoin. Also removing sleeps doesn't make any difference.
What's the reasoning for this behavior? What mystery is under the hood of Join() method and execution of Main method?

Join() works as you expect it to, the issue here is with the assumption that the thread running Main() terminates when Main() returns, which is not always the case.
Your Main() method is called by the .NET framework, and when the method returns, there is additional code executed by the framework before the main thread (and hence the process) exits. Specifically, one of the things the framework does as part of the post-Main code is wait for all foreground threads to exit.
This essentially results in a classic deadlock situation - the main thread is waiting for your worker thread to exit, and your worker thread is waiting for the main thread to exit.
Of course, if you make your worker thread a background thread, (by setting IsBackground = true before starting it) then the post-Main code won't wait for it to exit, eliminating the deadlock. However your Join() will still never return because when the main thread does exit, the process also exits.
For more details on the framework internals that run before and after Main(), you can take a look at the .NET Core codebase on GitHub. The overall method that runs Main() is Assembly::ExecuteMainMethod, and the code that runs after Main() returns is Assembly::RunMainPost.

Related

CLR via C# 4th Ed. - Confused about waiting for Task deadlock

Jeffrey Richter pointed out in his book 'CLR via C#' the example of a possible deadlock I don't understand (page 702, bordered paragraph).
The example is a thread that runs Task and call Wait() for this Task. If the Task is not started it should possible that the Wait() call is not blocking, instead it's running the not started Task. If a lock is entered before the Wait() call and the Task also try to enter this lock can result in a deadlock.
But the locks are entered in the same thread, should this end up in a deadlock scenario?
The following code produce the expected output.
class Program
{
static object lockObj = new object();
static void Main(string[] args)
{
Task.Run(() =>
{
Console.WriteLine("Program starts running on thread {0}",
Thread.CurrentThread.ManagedThreadId);
var taskToRun = new Task(() =>
{
lock (lockObj)
{
for (int i = 0; i < 10; i++)
Console.WriteLine("{0} from Thread {1}",
i, Thread.CurrentThread.ManagedThreadId);
}
});
taskToRun.Start();
lock (lockObj)
{
taskToRun.Wait();
}
}).Wait() ;
}
}
/* Console output
Program starts running on thread 3
0 from Thread 3
1 from Thread 3
2 from Thread 3
3 from Thread 3
4 from Thread 3
5 from Thread 3
6 from Thread 3
7 from Thread 3
8 from Thread 3
9 from Thread 3
*/
No deadlock occured.
J. Richter wrote in his book "CLR via C#" 4th Edition on page 702:
When a thread calls the Wait method, the system checks if the Task that the thread is waiting for has started executing. If it has, then the thread calling Wait will block until the Task has completed running. But if the Task has not started executing yet, then the system may (depending on the TaskScheduler) execute the Trask by using the thread that called Wait. If this happens, then the thread calling Wait does not block; it executes the Task and returns immediatlely. This is good in that no thread has blocked, thereby reducing resource usage (by not creating a thread to replace the blocked thread) while improving performance (no time is spet to create a thread an there is no contexte switcing). But it can also be bad if, for example, thre thread has taken a thread synchronization lock before calling Wait and thren the Task tries to take the same lock, resulting in a deadlocked thread!
If I'm understand the paragraph correctly, the code above has to end in a deadlock!?
You're taking my usage of the word "lock" too literally. The C# "lock" statement (which my book discourages the use of), internally leverages Monitor.Enter/Exit. The Monitor lock is a lock that supports thread ownership & recursion. Therefore, a single thread can acquire this kind of lock multiple times successfully. But, if you use a different kind of lock, like a Semaphore(Slim), an AutoResetEvent(Slim) or a ReaderWriterLockSlim (without recursion), then when a single thread tries to acquire any of these locks multiple times, deadlock occurs.
In this example, you're dealing with task inlining, a not-so-rare behavior of the TPL's default task scheduler. It results in the task being executed on the same thread which is already waiting for it with Task.Wait(), rather than on a random pool thread. In which case, there is no deadlock.
Change your code like below and you'll have a dealock:
taskToRun.Start();
lock (lockObj)
{
//taskToRun.Wait();
((IAsyncResult)taskToRun).AsyncWaitHandle.WaitOne();
}
The task inlining is nondeterministic, it may or may not happen. You should make no assumptions. Check Task.Wait and “Inlining” by Stephen Toub for more details.
Updated, the lock does not affect the task inlining here. Your code still runs without deadlock if you move taskToRun.Start() inside the lock:
lock (lockObj)
{
taskToRun.Start();
taskToRun.Wait();
}
What does cause the inlining here is the circumstance that the main thread is calling taskToRun.Wait() right after taskToRun.Start(). Here's what happens behind the scene:
taskToRun.Start() queues the task for execution by the task scheduler, but it hasn't been allocated a pool thread yet.
On the same thread, the TPL code inside taskToRun.Wait() checks if the task has already been allocated a pool thread (it hasn't) and executes it inline on the main thread. In which case, it's OK to acquired the same lock twice without a deadlock.
There is also a TPL Task Scheduler thread. If this thread gets a chance to execute before taskToRun.Wait() is called on the main thread, inlining doesn't happen and you get a deadlock. Adding Thread.Sleep(100) before Task.Wait() would be modelling this scenario. Inlining also doesn't happen if you don't use Task.Wait() and rather use something like AsyncWaitHandle.WaitOne() above.
As to the quote you've added to your question, it depends on how you read it. One thing is for sure: the same lock from the main thread can be entered inside the task, when the task gets inlined, without a deadlock. You just cannot make any assumptions that it will get inlined.
In your example, no deadlock occurs because the thread scheduling the task and the thread executing the task happen to be the same. If you were to modify the code such that your task ran on a different thread, you would see the deadlock occur, because two threads would then be contending for a lock on the same object.
Your example, modified to create a deadlock:
class Program {
static object lockObj = new object();
static void Main(string[] args) {
Console.WriteLine("Program starts running on thread {0}",
Thread.CurrentThread.ManagedThreadId);
var taskToRun = new Task(() => {
lock (lockObj) {
for (int i = 0; i < 10; i++)
Console.WriteLine("{0} from Thread {1}",
i, Thread.CurrentThread.ManagedThreadId);
}
});
lock (lockObj) {
taskToRun.Start();
taskToRun.Wait();
}
}
}
This example code has two standard threading problems. To understand it, you first have to understand thread races. When you start a thread, you can never assume it will start running right away. Nor can you assume that the code inside the thread arrives at a particular statement at a particular moment in time.
What matters a great deal here is whether or not the task arrives at the lock statement before the main thread does. In other words, whether it races ahead of the code in the main thread. Do model this as a horse race, the thread that acquired the lock is the horse that wins.
If it is the task that wins, pretty common on modern machines with multiple processor cores or a simple program that doesn't have any other threads active (and probably when you test the code) then nothing goes wrong. It acquires the lock and prevents the main thread from doing the same when it, later, arrives at the lock statement. So you'll see the console output, the task finishes, the main thread now acquires the lock and the Wait() call quickly completes.
But if the thread pool is already busy with other threads, or the machine is busy executing threads in other programs, or you are unlucky and you get an email just as the task starts running, then the code in the task doesn't start running right away and it is the main thread that acquired the lock first. The task can now no longer enter the lock statement so it cannot complete. And the main thread can not complete, Wait() will never return. A deadly embrace called deadlock.
Deadlock is relatively easy to debug, you've got all the time in the world to attach a debugger and look at the active threads to see why they are blocked. Threading race bugs are incredibly difficult to debug, they happen too infrequently and it can be very difficult to reason through the ordering problem that causes them. A common approach to diagnose thread races is to add tracing to the program so you can see the order. Which changes the timing and can make the bug disappear. Lots of programs were shipped with the tracing left on because they couldn't diagnose the problem :)
Thanks #jeffrey-richter for pointing it out, #embee there are scenario when we use locks other than Monitor than a single thread tries to acquire any of these locks multiple times, deadlock occurs. Check out the example below
The following code produce the expected deadlock. It need not be nested task the deadlock can occur without nesting also
class Program
{
static AutoResetEvent signalEvent = new AutoResetEvent(false);
static void Main(string[] args)
{
Task.Run(() =>
{
Console.WriteLine("Program starts running on thread {0}",
Thread.CurrentThread.ManagedThreadId);
var taskToRun = new Task(() =>
{
signalEvent.WaitOne();
for (int i = 0; i < 10; i++)
Console.WriteLine("{0} from Thread {1}",
i, Thread.CurrentThread.ManagedThreadId);
});
taskToRun.Start();
signalEvent.Set();
taskToRun.Wait();
}).Wait() ;
}
}

What happens to the main thread in this case

I have the following multithreaded program:
class Program{
static void main(){
(new Thread(DoSomething)).Start();
}
static void DoSomething(){
// Dome something here...
}
}
A couple of questions:
Does the main thread exit after spinning off the child thread?
If it does exit and the child thread is a background thread: Is the main process going to exit or will it wait for the background thread to finish?
"By default, threads you create explicitly are foreground threads. Foreground threads keep the application alive for as long as any one of them is running, whereas background threads do not. Once all foreground threads finish, the application ends, and any background threads still running abruptly terminate.
class PriorityTest
{
static void Main (string[] args)
{
Thread worker = new Thread ( () => Console.ReadLine() );
if (args.Length > 0) worker.IsBackground = true;
worker.Start();
}
}
If this program is called without any arguments, the worker thread will take foreground status and will wait on the ReadLine statement for the user to press Enter. Simultaniously, the main thread exits, but the application keeps running because a foreground thread is still alive.
However, if an argument is passed to Main(), the worker is assigned background status, and the program exits almost immediately as the main thread ends (terminating the ReadLine and the program)."
See Joseph Albahri's (a genius and great guy) page on threading for more information (it is where this was extracted from).
Typically, if you want to wait for the child thread to complete, you'd add a x.Join(); line (where x is the variable of your thread) wherever you want your main thread to stop and wait for the child to complete.
EDIT: So, yes, the main thread will exit unless one of three cases occurs:
a) the spawned thread completes before the rest of the main thread code (if you add any)
b) You have a condition that waits for the thread to complete (such as the Join statement I mentioned, but there are other ways too).
c) The main thread goes into a semi-infinite loop (such as a game/graphics engine).
In your bare-bones example, it will exit for sure (given your question's parameters, a background thread).
EDIT2: Sorry, I seem to have dodged your second question (and actually only considered background threads the whole while). If it's a background thread it will exit as I've explained, if it's foreground then it shouldn't (though I don't have much experience with foreground threads, so I can't say for sure).
So to answer your questions: Yes, the main thread exits. Yes, if the child is specifically a background thread, the process will exit as well.
EDIT3: Final edit, I promise. I just wanted to add some code so that you could prove the answer yourself (which is always nice to be able to do):
static void Main(string[] args)
{
Thread thready = new Thread(DoSomething);
thready.IsBackground = true;
thready.Start();
}
static void DoSomething()
{
while (true)
{
Console.Write("thread's looping \n");
}
}
By toggling the thready.IsBackground = true; to thready.IsBackground = false; you get a program that runs forever (not exiting until the thread does). Leaving it as true will exit very quickly.
Depends on Thread.IsBackground.
The process will not exit before all the foreground threads finish. In the following example...
class Program {
static void Main(string[] args) {
(new Thread(DoSomething)).Start();
}
static void DoSomething() {
Thread.Sleep(5000);
}
}
...the process will exit after 5 seconds.
But in this example...
class Program {
static void Main(string[] args) {
(new Thread(DoSomething) { IsBackground = true }).Start();
}
static void DoSomething() {
Thread.Sleep(5000);
}
}
...the process will exit (almost) immediately. The effect on the child background thread that is still running is similar to forcibly killing the process, so avoid doing that if possible.
main process thread will definitely exit...
edit: i rechecked the docs and found that IsBackground property is false by default...which means the main thread will wait...the earlier response ws with regards to the 2nd question

.NET C# Thread exception handling

I thought I understood this, and am a bit embarrassed to be asking, but, can someone explain to me why the breakpoint in the exception handler of following code is not hit?
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Thread testThread = new Thread(new ParameterizedThreadStart(TestDownloadThread));
testThread.IsBackground = true;
testThread.Start();
}
static void TestDownloadThread(object parameters)
{
WebClient webClient = new WebClient();
try
{
webClient.DownloadFile("foo", "bar");
}
catch (Exception e)
{
System.Console.WriteLine("Error downloading: " + e.Message);
}
}
You're creating a thread, setting it to be a background thread, and starting it. Your "main" thread is then finishing. Because the new thread is a background thread, it doesn't keep the process alive - so the whole process is finishing before the background thread runs into any problems.
If you write:
testThread.Join();
in your Main method, or don't set the new thread to be a background thread, you should hit the breakpoint.
Your thread is a Background thread (you set it so yourself). This means that when the application completes, the thread will be shut down without being given chance to complete.
Because your main has no further content, it exits immediately and both the application and your thread are terminated.
If you were to add a testThread.Join() call then your thread would complete before the app exited and you'd see the exception caught.
Most likely your background thread isn't started before Main exits - starting a new thread may take a while. Since the additional thread is a background thread it is terminated when Main exits.
For demo purposes, you could have your main method wait - e.g. on user input. This would allow the background thread to start running.
Since the new thread's IsBackground is true, it won't prevent the process from terminating. At the end of Main() the only foreground thread terminates, shutting down the process before the other thread gets that far.
Probably because the main thread is ending before the worker thread. Try adding
Console.ReadKey();
at the end of your Main method.

How can I ensure a determenistic result for this multithreading problem?

Consider the following test snippet:
// act
AutoResetEvent workDoneEvent = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate
{
ProcessAndSignal(processor, workDoneEvent);
}, null);
// let worker thread have a go
workDoneEvent.WaitOne();
blockingFetcher.WaitForNextMessage = false;
// assert
Assert.That(processor.StopCause, Is.Null);
}
private static void ProcessAndSignal(MessageProcessor processor, AutoResetEvent workDoneEvent)
{
workDoneEvent.Set();
// this invocation will block until the WaitForNextMessageFlag is set
processor.ProcessMessages();
}
Ideal scenario:
ProcessAndSignalMethod is queued on the thread pool but does not start to execute.
The main thread blocks (autoResetEvent.WaitOne())
A worker thread starts to execute the "ProcessAndSignal" method
The worker threads has enough time to signal the flag and start execution of the ProcessMessages method
The main thread is spawned back into life and sets the property which will cause the ProcessAndSignal method to complete gracefully
Can the following scenario occur?
1) ProcessAndSignal() will start to execute before the main thread sets the AutoResetEvent to WaitOne() which will cause a deadlock (the processor.ProcessMessages() will go into an infinitive loop)
Yes, the scenario can occur. Yes it can deadlock if you don't declare the bool variable as volatile. Just don't use a bool, use an event like you did.
The logic looks weird, it smells like you are trying to let the main thread wait for the processing to be completed. The workDoneEvent doesn't actually signal that the work was done. Right now the main thread will check the assert before the worker is done, that can't be good. If the intention was that it signals that the worker is done then ProcessAndSignal should be the one calling Set(), at the end of the method. And the main thread should call WaitOne().
If this is at all accurate then you just should not use QUWI, just call ProcessAndSignal directly without using a thread. Far more efficient, zero odds for threading problems.

Dispatcher.Invoke hangs when the main thread called Thread.Join

I am having a problem, for which I am not able to find a solution. The problem is as follows:
In the main thread (the default thread), I am starting a thread and then immediately in the main thread, I wait for the thread's exit by calling Thread.Join on the spawned thread. When I do that if the spawned thread tries to callback in the main thread's context by calling Dispatcher.Invoke, it hangs. Any ideas how I can allow the callback?
The callback has the logic to signal the thread to exit. Without executing the callback, the thread will never exit, and so the main thread is also stuck.
What's the point of starting a new thread if you just wait for it to complete ? Just do the work on the main thread...
I'm not exactly sure what you are asking but you may try BeginInvoke instead of Invoke
If you're only going to be waiting on the thread to terminate, you could simply have a polling loop, like this:
// var otherThread = ...;
volatile bool terminate = false;
while (!terminate)
{
Thread.Sleep(100);
}
otherThread.Join();
Then, leave it up to the callbacks to set the terminate flag to true once you're ready to join.
I had a similar problem which I finally solved in this way:
do{
// Force the dispatcher to run the queued operations
Dispatcher.CurrentDispatcher.Invoke(delegate { }, DispatcherPriority.ContextIdle);
}while(!otherthread.Join(1));
This produces a Join that doesn't block because of GUI-operations on the other thread.
The main trick here is the blocking Invoke with an empty delegate (no-operation), but with a priority setting that is less than all other items in the queue. That forces the dispatcher to work through the entire queue. (The default priority is DispatcherPriority.Normal = 9, so my DispatcherPriority.ContextIdle = 3 is well under.)
The Join() call uses a 1 ms time out, and re-empties the dispatcher queue as long as the join isn't successful.

Categories