I am trying to understand data parallelism and processes in C#(Reference) and am getting a bit confused by the behavior. I may be missing some really basic concept , but it would be great if anyone could explain this
So I have the following code :-
private static void Process()
{
Process _process = new Process();
_process.StartInfo.FileName = "C:\\Windows\\notepad.exe";
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.RedirectStandardOutput = true;
// Start the process
_process.Start();
_process.BeginOutputReadLine();
Task task = Task.Factory.StartNew(() => MonitorProcess());
Console.WriteLine("Main ");
}
private static void MonitorProcess()
{
Console.WriteLine("Inside Monitor");
string x = null;
x = x.Trim();
}
Now my expectation is that "Main" should never be printed to the console since there is a null reference exception in the MonitorProcess method . I don't want to use task.Wait() to catch and throw the exception since that will wait for the task to complete.
So why does this happen and how can i get around this so that code execution is stopped at the exception in the MonitorProcess method ?
A task is run in a seperate thread (one from the thread pool). The exception isn't thrown in the main thread, so why should the main thread stop?
Since the two threads execute in parallel, it might even be possible for your Process method to print (and return) before the exception is even thrown in the MonitorProcess method.
If you want your main thread to stop, you have to propagate the exception to it. You can find a few examples how to do this here: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was
But doing this without waiting in the main thread will still not stop the main thread from printing because, as I already said, that code might have already been executed.
Related
The goal is to start a Task, that loads some resources from the disk, on the UI thread, and then when it is finished to check if it threw an Exception without blocking the UI thread, and if it did, to rethrow the exception on the UI thread so the program ends and I get a stack trace.
I have been able to figure out that I can start a Task on a background thread without blocking, and awaiting the Task blocks the main thread.
I absolutely can not call await on the Task, because it would block the UI thread, but it appears I need to call it to access the Exception property after the Task has completed. I also can not use continueWith, because that also runs asynchronously, so propagating the exception from there will not work.
The docs I see all block to wait for the Exception.
https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?view=net-7.0#WaitingForOne
For the Exception property of the Task, it would be nice if I could use something like RegisterPropertyChangedCallback, but that is not an available method in the Task object.
This is the code where I want to rethrow an Exception in the UI thread without blocking it
public TitlePage()
{
this.InitializeComponent();
string baseFolder = AppDomain.CurrentDomain.BaseDirectory;
string folder = baseFolder + #"Assets\";
Task task = DataSource.Load(folder);
// This is where I want to rethrow the Exception if it was thrown
// unless I can end the program and print the stack trace
// from the Task when it throws an Exception.
// Note that this is inside the constructor of a Page class;
// it is vital that the UI thread is not blocked.
}
Use a "factory method": a static method that returns a new instance of the class. Then make the constructor empty and private to prevent anyone from creating an instance without using the factory method.
Something like this:
private TitlePage() {}
public static async Task<TitlePage> CreateTitlePage()
{
var titlePage = new TitlePage();
titlePage.InitializeComponent();
string baseFolder = AppDomain.CurrentDomain.BaseDirectory;
string folder = baseFolder + #"Assets\";
Task task = DataSource.Load(folder);
await task;
return titlePage;
}
Because this static method is inside the class, you can call other private methods, including the constructor.
Then you call it like this:
var newTitlePage = await TitlePage.CreateTitlePage();
If it is called on the UI thread, any exception will be thrown on the UI thread.
Rethrowing within the UI thread an exception that was thrown by a side-task is just a special case of the more general case of communicating to the UI thread any kind of result produced by the side-task.
(In other words, today you think you only need to throw an exception; tomorrow you are likely to discover that you also need to obtain a result.)
For this purpose I like to communicate a Result class like the one found in Scala, (and of which various implementations exist for C#,) but this is not necessary; the Task object can also be communicated after Task.IsCompleted becomes true; The UI thread can check whether it represents failure with Task.IsFaulted, and if so, it can get the exception with Task.Exception; otherwise, it can get the result with Task<T>.Result.
So, the question now becomes how to have a Task communicate a result back to the UI thread, once the task is complete, without the UI thread having to wait for the task to complete.
To do this, you can pass to the task a "task completion action" in the form of an Action<R> delegate, where R is the type of the result, and to implement this delegate in such a way that it posts the result into the message queue of the UI thread.
Under WPF, posting something into the UI thread is done with Dispatcher.BeginInvoke().
So, here is some code:
using Sys = System;
using Wpf = System.Windows;
using WpfThreading = System.Windows.Threading;
private void TaskCompletionAction( R result )
{
Assert( not-in-UI-thread );
Sys.Action action = () => ReceiveResult( result );
Wpf.Application.Current.Dispatcher.BeginInvoke(
WpfThreading.DispatcherPriority.Background,
action );
}
private void ReceiveResult( R result )
{
Assert( in-UI-thread );
...do something with the result...
}
I am reading multithreading in Albahari's c# in a nutshell. He says that if a thread (for example Main thread) creates and starts a worker thread , then an exception thrown by the worker thread cannot directly be caught and handled by the creating thread. Let me quote him verbatim:
"Any try / catch / finally blocks in effect when a thread is created are of no
relevance to the thread when it starts executing. Consider the following
program:
public static void Main()
{
try
{
Thread workerThread = new Thread (Go);
workerThread.Start();
}
catch (Exception ex)
{
// We'll never get here!
Console.WriteLine ("Exception!");
}
}
static void Go()
{
throw null; // Throws a NullReferenceException
}
Albahari goes on to say that:
"The try / catch statement in this example is ineffective, and the newly
created thread will be encumbered with an unhandled
NullReferenceException . This behavior makes sense when you consider
that each thread has an independent execution path."
So here is the crux of my question:
I don't get the relevance of "each thread has an independent execution path". I mean why should it matter if the execution paths are independent ? I mean when the workerThread throws an unhandled exception -- why can't the CLR just halt the Main thread and hand over the exception object to the catch block in the Main? What's stopping it ??
[NOTES:
The other related question How do I handle exceptions from worker threads and main thread in a single catch block? is NOT asking the same question --- and none of the elaborate answers express WHY can't the CLR marshal an unhandled exception from a worker thread to the Main thread
Similar question is asked about another language , C++, -- where the answers suggest that it has something to do with the two threads having different stacks and the logical impossibility of mixing the two while unwinding the stack during exception handling. I'm not sure whether those answers apply here to a managed execution environment , like that of c#.
]
The main thread might have already finished executing.
I know it is hard to understand at first, but the worker thread is not executed like a method call even if it looks like that. The thread is created inside that try-block, but the execution might happen much later or not at all. Source code in text form can not make this visible. There seems to be some kind of "spacial" proximity of the try-block and the thread, but the moment the thread is created, the spacial proximity is gone. The try block only handles any exceptions that happen while the thread is created, but the it is "detached" from it.
Analogy: The main thread is the manager (team lead) and the worker thread(s) are the workers (team members) reporting to that manager. The workers are working in their home office. In the morning the manager is sending them emails with tasks for the day ("execute method Go"). Since the manager can not see the workers doing their work, she can only notice any progress or lack of it, if the workers send progress reports from time to time. If workers fall off their chairs or down the stairs (exceptions), the manager would not know. The workers need to make sure to catch such exceptions and send an appropriate message to the manager to let her know. The manager is (in this case) not waiting around after sending the initial emails, but is doing other work in the meantime.
You are asking why the CLR can't halt the Main thread, and handle the exception of the child thread. Do you mean the main thread should always suspend execution automatically, immediately after launching a new Thread? This would be very unhelpful, since a program could then have at a maximum one and only one active thread. It would be the end of multithreading as we know it! So you probably mean that the CLR should offer a mechanism to do this suspension of execution on demand. Although such a mechanism is indeed not available, you can do something very close to it using tasks:
public static void Main()
{
try
{
Task workerTask = new Task(() =>
{
throw null;
}, TaskCreationOptions.LongRunning); // Use a dedicated thread
workerTask.Start();
workerTask.Wait();
}
catch (Exception ex)
{
Console.WriteLine("Exception!"); // It happens!
}
}
Everyone knows thread should exit gracefully, but now I have to kill a thread.
When there is a request comming, I start a thread as below
_thread = new Thread(ProcessTemplate);
_thread.Start();
In the ProcessTemplate method, it takes use of Google V8 to compile and run a javascript code sent from client-side.
The problem is, the javascript sent from client-side could be buggy and cause an infinite loop.
Hence, I count the time since the thread start and if the javasctript execution time exceeds 10 second, I kill the thread like
try
{
_thread.Abort();
}
catch
{
}
It works but also affects the current thread which started the _thread.
I receive "Thread was being aborted." exception from current thread.
how to avoid/ignore the exception?
I receive "Thread was being aborted." exception from current thread.
You receive this exception in the background thread, not in the main thread that started it as the documentation explains:
Raises a ThreadAbortException in the thread on which it is invoked, to
begin the process of terminating the thread. Calling this method
usually terminates the thread.
So inside this background thread you can handle this exception:
_thread = new Thread(() =>
{
try
{
ProcessTemplate();
}
catch (ThreadAbortException ex)
{
// the thread was aborted, call ResetAbort to
// avoid rethrowing the exception
Thread.ResetAbort();
}
);
Probably you are seeing the main thread affected because in certain cases unhandled exceptions in background threads could bring the AppDomain down. So normally you should handle those exceptions.
You can use a Task and pass it a CancellationToken
Link
I receive "Thread was being aborted." exception from current thread.
Because that's what happens when you call Thread.Abort:
When this method is invoked on a thread, the system throws a
ThreadAbortException in the thread to abort it. ThreadAbortException
is a special exception that can be caught by application code, but is
re-thrown at the end of the catch block unless ResetAbort is called.
You should catch the ThreadAbortException in your background thread and make sure its handled.
I would suggest that instead of using the rather dangerous abort, use the new features of the Task Parallel Library that allow for cooperative cancellations:
var cts = new CancellationTokenSource();
var ct = cts.Token;
var javaScriptTask = await Task.Run(() => ProcessTemplate, cts.Token);
And inside ProcessTemplate, monitor that CancellationToken:
ct.ThrowIfCancellationRequest();
Or, if you really want full control when making blocking calls, you should spin a new process to run your tasks.
I have the following.
public static Thread testThread = new Thread(ThreadStart) {Name = "TestThread", IsBackground = true};
private void Form_Load()
{
testThread.Start()
}
private static void ThreadStart()
{
int count = 0;
try
{
while (true)
{
count++;
}
}
catch (Exception ex)
{
StreamWriter stream = new StreamWriter(File.OpenWrite("Exception.txt"));
stream.WriteLine(count + "\n" + ex);
stream.Flush();
stream.Close();
}
}
When I call Thread.Abort() I catch the exception and write out to the file.
However, if I instead close the application nothing is written.
I also have
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
But it doesn't appear an exception is ever thrown.
I suppose adding a question is prudent.
What happens to a running background thread when the parent processes exits?
My understanding was a ThreadAbortException is thrown to exit the thread.
If this is the case, how can the ThreadAbortException be caught in order to clean up resources that may be present in the thread?
First of all, the application probably isn't exiting, because you are not making these into background threads. My guess is that Task Manager will show copies of your EXE running unexpectedly. You need to set Thread.IsBackground to true on the thread object before calling Start.
Secondly, the behavior that you expect is explicitly debunked by the documentation:
Note
When the common language runtime (CLR) stops background threads,
after all foreground threads in a managed executable have ended, it
does not use System.Threading.Thread.Abort. Therefore, you cannot use
ThreadAbortException to detect when background threads are being
terminated by the CLR.
EDIT:
When a process is exiting, there is no need to clean up resources held by the worker threads because, you know, the process is exiting. The contract with regard to background threads is that they can be killed at any time when the process exits. Therefore, if your background threads are doing something that requires transactional correctness, they probably should not be background threads. Make 'em foreground threads and have them periodically check or wait on a reset event to see whether they should exit and allow the process to end.
When the CLR shuts down a process it does not call Thread.Abort or anything similar. Your thread methods will not exit like your main method.
The first thing it does when you leave the main method or call Environment.Exit is to finalize all objects with a timeout (it was 2s in .NET 2.0) then it will continue to terminate the application regardless of the current pending finalizers.
Next the Critical Finalizers are called.
Then all threads are suspended so they do not cause harm while the CLR is shutting down.
You application has exited.
If the IsBackground property of your thread is false, then your thread would remain alive, even when the main window of your application is closed.
The best way to control the lifetime of background threads is to create sentinels, typically implemented as volatile bool fields, which the code within the thread checks at regular intervals (for example, on every iteration). The thread should stop executing when the sentinel indicates that the application is terminating.
The following code shows the use of a sentinel to terminate the thread after 200 milliseconds:
public static Thread testThread = new Thread(ThreadStart)
{
Name = "TestThread",
IsBackground = false // Allow thread to terminate naturally
};
private static volatile bool isTerminating = false; // Sentinel
private void Form_Load()
{
testThread.Start();
Thread.Sleep(200); // Sleep 200 milliseconds
isTerminating = true; // Set sentinel to terminate thread
}
private static void ThreadStart()
{
int count = 0;
while (!isTerminating) // Keep looping until sentinel is set
count++;
using (StreamWriter stream = new StreamWriter(File.OpenWrite("Result.txt")))
{
stream.WriteLine(count);
stream.Flush();
}
}
Edit: To answer your last question, “How can the ThreadAbortException be caught in order to clean up resources that may be present in the thread?” You can use an ordinary catch block. ThreadAbortException may be caught like any other exception, but it will automatically be raised again at the end of the catch block. However, as Chris mentioned, if the process is exiting, the ThreadAbortException is not raised at all.
Why exceptions thrown within a task are silent exception and you never know if a certain exception has been thrown
try
{
Task task = new Task(
() => {
throw null;
}
);
task.Start();
}
catch
{
Console.WriteLine("Exception");
}
the program run successfully in a complete silence!
where the behavior of threads is different
try
{
Thread thread = new Thread(
() => {
throw null;
}
);
thread .Start();
}
catch
{
Console.WriteLine("Exception");
}
a null pointer exception will be thrown in this case.
What is the difference?
The behaviour of that scenario depends on what framework you have; in 4.0, you actually need to be careful - if you don't handle TaskScheduler.UnobservedTaskException, it will error later when it gets collected/finalized, and will kill your process.
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
Trace.WriteLine(args.Exception.Message); // somebody forgot to check!
args.SetObserved();
};
This changes in 4.5, IIRC.
To check the outcome of a Task that might fail, you could register a continuation - i.e. call ContinueWith and check the result's exception. Alternatively, accessing the .Result of the task (which would also do an implicit Wait()) will re-surface the exception that happened. It is good to observe the result of a task, as that clears the finalization flag, meaning it can be collected more cheaply.
No, tasks are not threads. Tasks represent a high level abstraction - they are a unit of work that is inherently parallelisable. Threads run units of work.
In your first example, you create a unit of work and then tell it to run itself (how it does so is an implementation detail of Task). Whereas in your second example you explicitly schedule a unit of work (it would appear in a different manner to the implementation of Task).
The following assumes .NET 4.0, and the using the default TaskScheduler.
First of all notice that the exceptions are raised inside the delegates you pass, so they are raised in a different thread, not in the one you (logically) are doing your catch. So somehow the exception must be propagated from the thread that executes your delegate / lambda code to the one that started the thread/task.
Note that for Task, I think that the library can also choose not to run it on it's own thread, but rather on the calling thread (but I'm not sure if that was only true for Parallel.ForEach, etc. and not for a "naked" Task object).
For that two happen, two things must be fulfilled:
The calling thread is still active. Otherwise there is nothing left that could actually perform the catch.
The exception that was caused in the thread/task must somehow be preserved and reraised for you to catch it.
Having that said, both of your examples don't wait for the thread/task to finish. In the first example you're missing a task.Wait() (or similar) and in the second a thread.Join(). Depending on your test codes timing behavior this may mean that you may never be able to observe the exception from the thread/task (item 1 above).
Even if you add the two calls this is what happens for me (again .NET 4.0):
Task example: the call to task.Wait() actually reraises the exception originally left unhandled in the task's delegate (this is what the TPL will do for you internally), it does wrap it inside a System.AggregateException, which you could/would see if you'd use something more precise then a flat "catch-all".
Thread example: the exception raised by the delegate remains unhandled and your application exits (unless you do anything to deal with unhandled exceptions differently)
In other words I would have the examples as follows:
// Thread example
var thread = new Thread(() => { throw null; });
thread.Start();
thread.Join();
// Should never reach here, depending on timing sometimes not even
// until the Join() call. The process terminates as soon as the other
// thread runs the "throw null" code - which can logically happen somewhere
// after the "start" of the "Start()" call.
// Task example
try
{
var task = new Task(() => { throw null; });
task.Start();
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine("Exception: " + ex);
}
I think you are not getting exception in case of Task because you are not waiting for exception in the main thread. You are just continuing. Put task.Wait() and you will get the exception in main thread.