AppDomain.Unload throws ThreadAbortException exception - c#

Having
public class ObjFromOtherAppDomain : MarshalByRefObject
{
public async void Do(MarshalableCompletionSource<bool> source)
{
await Task.Delay(1000);
source.SetResult(true);
}
}
public class MarshalableCompletionSource<T> : MarshalByRefObject
{
private readonly TaskCompletionSource<T> tsc = new TaskCompletionSource<T>();
public void SetResult(T result) => tsc.SetResult(result);
public void SetException(Exception[] exception) => tsc.SetException(exception);
public void SetCanceled() => tsc.SetCanceled();
public Task<T> Task => tsc.Task;
}
Doing
Create new AppDomain
Create an instance of ObjFromOtherAppDomain within the new AppDomain
invoke Do method passing MarshalableCompletionSource in order later to know when async Do method is completed.
Once Do method is completed, trying to Unload the AppDomain
public static async Task Main()
{
var otherDomain = AppDomain.CreateDomain("other domain");
var objFromOtherAppDomain = (ObjFromOtherAppDomain)otherDomain
.CreateInstanceAndUnwrap(
typeof(ObjFromOtherAppDomain).Assembly.FullName,
typeof(ObjFromOtherAppDomain).FullName);
var source = new MarshalableCompletionSource<bool>();
objFromOtherAppDomain.Do(source);
await source.Task;
//await Task.Yield();
AppDomain.Unload(otherDomain);
}
Getting
System.Threading.ThreadAbortException: 'Thread has aborted. (Exception
from HRESULT: 0x80131530) exception
Fix
Uncomment await Task.Yield(); line and Unload works well.
Short analysis
Main thread enters Do method and on the line await Task.Delay(1000), Main thread returns back to Main method, while new background thread gets pulled from ThreadPool (it's happening in otherDomain) and continues execution of continuation, in this case, rest of the Do method.
After that, the same (background) thread starts executing rest of the Main method (the part after await source.Task)
At that moment background thread hits AppDomain.Unload(otherDomain), it should be done in otherDomain and happily unload it, but, apparently, it's not.
If i'll yield (release, set free) that background thread by await Task.Yield(), new Background thread comes into play and does AppDomain.Unload happily.
Why is that?

With the help of my colleague, I found out the issue.
Short
When the result is set to TaskCompletionSource, continuation attached to TaskCompletionSource.Task runs on the same thread that called TaskCompletionSource.SetResult, causing Do method not to be completed at the time AppDomain.Unload is called.
Detailed
Main -> objFromOtherAppDomain.Do(source); - Thread1 starts execution of Do method
Do -> await Task.Delay(1000); - Thread1 returns back to Main method and awaits source.Task, Thread2 continues execution of Do method.
Do -> source.SetResult(true); - Thread2 sets the result to MarshalableCompletionSource.Task and continues execution of Main method (Without finishing up the Do method)
Main -> AppDomain.Unload(otherDomain); - Thread2 tries to unload the AppDomain, but since Do method isn't yet finished, unload fails.
On the other hand, if we do await Task.Yield(), it will cause Thread2 to return from Main method to Do method and finish it up, after that AppDomain can be unloaded.
Related
Calling TaskCompletionSource.SetResult in a non blocking manner

Related

How do I avoid async void?

Note: Turns out this issue is specific to Unity.
I read that async void was to be avoided. I am trying to do so using Result, but my application keeps locking up. How can I avoid using async void?
public async void PrintNumberWithAwait()
{
int number = await GetNumber();
Debug.Log(number); //Successfully prints "5"
}
public void PrintNumberWithResult()
{
int number = GetNumber().Result;
Debug.Log(number); //Application Freezes
}
private async Task<int> GetNumber()
{
await Task.Delay(1000);
return 5;
}
I thought this was correct, but I must be missing something. How do I use async/await without having async void?
I ran my tests separately with the following code (commented one out at a time):
PrintNumberWithAwait();
PrintNumberWithResult();
Short Version
Unity's Synchronization Context is single threaded. So:
Result hangs until the task completes
The task cannot complete because continuation is pushed on Main Thread, that is waiting
Detailed Version
You said you are using Unity. Unity is "99%" a single-threaded framework. So I suppose this code is executed on the Main, UI Thread.
Let's step into what your code do in details, when executing PrintNumberWithResult().
[Main Thread] From PrintNumberWithResult() you call GetNumber()
[Main Thread] You execute await Task.Delay()
[Main Thread] The code under the await line (the return 5) is "pushed" into a "List of code" to execute after that the Task (The Delay) is completed.
Small insight: This sort of list of "continuations code" is handled by a
class called SynchronizationContext (It is a c# thing, not a Unity thing). You can think this class as the guy that says HOW and WHEN the code between awaits are called. The standard .NET implementation uses a thread pool (so a set of threads) that will execute the code after the task is completed. It's like an "advanced callback". Now in Unity this is different. They implemented a custom Synchronization Context that ensures all the code is executed ALWAYS in the MAIN THREAD. We can continue now
[MAIN THREAD] The Delay Task is not completed yet, so you have an early return in the PrintNumberWithResult method, and you execute the .Result, that makes the Main Thread hangs there until the Task is completed.
[Deadlock]. 2 things are happening in this point. The Main Thread is waiting for the Task to complete. The Custom Unity's synchronization Context pushed the code above the await to be executed in the Main Thread. But The Main Thread is waiting! So it will never be free to execute that code.
Solution
Never call .Result.
If you want to fire and forget a task operation use Task.Run(() => ). But Wait! that's not a good idea in Unity! (Maybe it is in other .NET applications).
If you use Task.Run() in Unity you are forcing the async code to be executed using the default .NET Synchronization context, that uses a thread pool, and that could cause some synchronization issues if you are calling some Unity related API.
What you want to do in that case is to use an async void (not really for reasons related to exception handling), an async Task method that you will never await (better), or maybe use a library as UniTask for async await using Unity (The best in my opinion).
You misunderstood what is meant by the async void that is to be avoided.
It doesn't mean you should never use a task with no result attached. It just says the asynchronous methods that invoke them should return a Task, not void.
Simply take the signature of your async method from
public async void PrintNumberWithAwait()
and replace void with Task
public async Task PrintNumberWithAwait()
{
int number = await GetNumber();
Debug.Log(number); //Successfully prints "5"
}
Now calling methods have the option of awaiting the result, when and if they choose to. Either:
await PrintNumberWithAwait();
Or
Task t = PrintNumberWithAwait();
// Do other stuff
// ...
await t;
This answer is pretty complete and explains the "issue"/subject very well.
But to extend it a little, your example with the async void "works" for one reason: For Debug.Log the synchronization context doesn't matter. You can safely Debug.Log from different threads and background tasks and Unity handles them in the console. BUT as soon as you would try to use anything from the Unity API that is only allowed on the main thread (basically everything that immediately depends on or changes the scene content) it might break since it is not guaranteed that await ends up on the main thread.
However, what now?
Nothing really speaks against using Thread and Task.Run in Unity!
You only have to make sure to dispatch any results back into the Unity main thread.
So I just wanted to give some actual examples of how this can be done.
Something often used is a so called "Main thread dispatcher" .. basically just a ConcurrentQueue which allows you to Enqueue callback Actions from just any thread and then TryDequeue and invoke these in an Update routine on the Unity main thread.
This looks somewhat like e.g.
/// <summary>
/// A simple dispatcher behaviour for passing any multi-threading action into the next Update call in the Unity main thread
/// </summary>
public class MainThreadDispatcher : MonoBehaviour
{
/// <summary>
/// The currently existing instance of this class (singleton)
/// </summary>
private static MainThreadDispatcher _instance;
/// <summary>
/// A thread-safe queue (first-in, first-out) for dispatching actions from multiple threads into the Unity main thread
/// </summary>
private readonly ConcurrentQueue<Action> actions = new ConcurrentQueue<Action>();
/// <summary>
/// Public read-only property to access the instance
/// </summary>
public static MainThreadDispatcher Instance => _instance;
private void Awake ()
{
// Ensure singleton
if(_instance && _instance != this)
{
Destroy (gameObject);
return;
}
_instance = this;
// Keep when the scene changes
// sometimes you might not want that though
DontDestroyOnLoad (gameObject);
}
private void Update ()
{
// In the main thread work through all dispatched callbacks and invoke them
while(actions.TryDequeue(out var action))
{
action?.Invoke();
}
}
/// <summary>
/// Dispatch an action into the next <see cref="Update"/> call in the Unity main thread
/// </summary>
/// <param name="action">The action to execute in the next <see cref="Update"/> call</param>
public void DoInNextUpdate(Action action)
{
// Simply append the action thread-safe so it is scheduled for the next Update call
actions.Enqueue(action);
}
}
Of course you need this attached to an object in your scene, then from anywhere you could use e.g.
public void DoSomethingAsync()
{
// Run SomethingWrapper async and pass in a callback what to do with the result
Task.Run(async () => await SomethingWrapper(result =>
{
// since the SomethingWrapper forwards this callback to the MainThreadDispatcher
// this will be executed on the Unity main thread in the next Update frame
new GameObject(result.ToString());
}));
}
private async Task<int> Something()
{
await Task.Delay(3000);
return 42;
}
private async Task SomethingWrapper (Action<int> handleResult)
{
// cleanly await the result
var number = await Something ();
// Then dispatch given callback into the main thread
MainThreadDispatcher.Instance.DoInNextUpdate(() =>
{
handleResult?.Invoke(number);
});
}
This makes sense if you have a lot of asynchronous stuff going on and want to dispatch them all at some point back to the main thread.
Another possibility is using Coroutines. A Coroutine is basically a bit like a temporary Update method (the MoveNext of the IEnumerator is called once a frame by default) so you can just repeatedly check if your task is done already on the main thread. This is what Unity uses themselves e.g. for UnityWebRequest and could looked somewhat like
public void DoSomethingAsync()
{
// For this this needs to be a MonoBehaviour of course
StartCorouine (SomethingRoutine ());
}
private IEnumerator SomethingRoutine()
{
// Start the task async but don't wait for the result here
var task = Task.Run(Something);
// Rather wait this way
// Basically each frame check if the task is still runnning
while(!task.IsCompleted)
{
// Use the default yield which basically "pauses" the routine here
// allows Unity to execute the rest of the frame
// and continues from here in the next frame
yield return null;
}
// Safety check if the task actually finished or is canceled or faulty
if(task.IsCompletedSuccessfully)
{
// Since we already waited until the task is finished
// This time Result will not freeze the app
var number = task.Result;
new GameObject (number.ToString());
}
else
{
Debug.LogWarning("Task failed or canceled");
}
}
private async Task<int> Something ()
{
await Task.Delay(3000);
return 42;
}

Wait() method of a task bloks the Task

I am working in Xamarin where I have a Task that I start at the first menupage, go through several other menupages, and then want to wait for it's completion when opening an endpage. To do this I save the task in a static field when starting it:
private static Task myTask;
public static void sync(User user)
{
if (myTask== null || myTask.IsCompleted) {
myTaskStarted = true;
//Note: do not trust on the variable being filled in immediately after the start of the task. It takes a minute. Use the flag
myTask= AsyncMyTask(user);
}
}
And then later I call a method from another page that is simply supposed to wait for myTask to finnish by calling myTask.Wait() after doing some checks on myTask having been started and not being null. But I see that once I call myTask.Wait() myTask is stuck and no longer progresses in the debugger. It's stuck. If I replace myTask.Wait() by myTask.Wait(1000) myTask is frozen for the duration of the timeout. After the timeout it continues. This is not the behaviour that is described in the documentation. Can anyone explain why the AsyncMyTask method is blocked when you call myTask.Wait() from the UI thread?
As requested: the AwaitMyTask method:
public async static Task<Boolean> AwaitMyTask()
{
if(!myTaskStarted && myTask== null)
{
return false;
} else
{
while (myTask== null)
{
Task.Delay(10);
}
}
//Stuck on the line below
myTask.Wait();
myTaskStarted = false;
return myTask.IsCompleted;
}
Task.Wait is a synchronously awaiting the task which blocks the thread. Unless you can point to a documentation stating something else, I'd say that it's expected behavior as described in https://msdn.microsoft.com/en-us/library/dd235635(v=vs.110).aspx
Wait is a synchronization method that causes the calling thread to wait until the current task has completed. ...

Why is the initial thread not used on the code after the awaited method?

I do not understand how is the control returned to the caller when using async- await, since when i execute this code, the first thread gets practically destroyed when calling task inside the awaited method, and the thread that gives the result executes all remaining code.Below i have also drawn a diagram of how i thought the execution is, but it seems it is wrong.
Assumed workflow according to "returning control to the caller":
Results
Main
public static string GetThreadId => Thread.CurrentThread.ManagedThreadId.ToString();
static async Task Main(string[] args) {
Console.WriteLine("From main before async call , Thread:" + GetThreadId);
string myresult = await TestAsyncSimple();
Console.WriteLine("From main after async call ,Thread:" + GetThreadId);
Console.WriteLine("ResultComputed:" + myresult+",Thread:"+GetThreadId);
Console.ReadKey();
}
Async Task
public static async Task<string> TestAsyncSimple() {
Console.WriteLine("From TestAsyncSimple before delay,Thread:" + GetThreadId);
string result=await Task.Factory.StartNew(() => {
Task.Delay(5000);
Console.WriteLine("From TestAsyncSimple inside Task,Thread:" + GetThreadId);
return "tadaa";
});
Console.WriteLine("From TestAsyncSimple after delay,Thread:" + GetThreadId);
return result;
}
Can anyone point me to the right direction?Also what causes the new thread to get spawned?Always when starting a Task ?Are there other "triggers" besides tasks that create new threads which will execute the remaining code?
async Main method is converted to something like this:
static void Main() {
RealMain().GetAwaiter().GetResult();
}
static async Task RealMain() {
// code from async Main
}
With that in mind, at "From main before async call" point you are on main application thread (id 1). This is regular (non thread pool) thread. You will be on this thread until
await Task.Factory.StartNew(...)
At this point, StartNew starts a new task which will run on a thread pool thread, which is created or grabbed from pool if already available. This is thread 3 in your example.
When you reach await - control is returned back to the caller, where caller in this case is thread 1. What this thread does after await is reched? It's blocked here:
RealMain().GetAwaiter().GetResult();
waiting for result of RealMain.
Now thread 3 has finished execution but TestAsyncSimple() has more code to run. If there were no synchronization context before await (the case here - in console application) - the part after await will be executed on available thread pool thread. Since thread 3 has finished execution of its task - it is available and is capable to continue execution of the rest of TestAsyncSimple() and Main() functions, which it does. Thread 1 all this time is blocked as said above - so it cannot process any continuations (it's busy). In addition it's also not a thread pool thread (but that is not relevent here).
After you reached Console.ReadKey and pressed a key - Main task finally completes, thread 1 (waiting for this task to complete) is unblocked, then it returns from real Main function and process is terminated (only at this point thread 1 is "destroyed").

When should Task.Run() be used?

What's the difference between these two approaches:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
Task<string> getStringTask = GetStringAsync();
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
and
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
getStringTask.Wait();
string result = getStringTask.Result;
Console.WriteLine(result);
}
I've seen a lot of people using the first approach and I'm not sure why. Is there any particular advantage? Which one is recommended for waiting async methods inside main of a Console Application?
Is there any particular advantage?
Usually with async methods the operation is initialized synchronously and then the wait can be asynchronous with await or syncrhnous with Wait(). The Main method can't be async so you are force to block with Wait() there or you can do a Console.ReadKey() to run until the user presses a key.
Task.Run(async () => ... ) can be quite useful when the async operation is expensive to initialize. That way you allow the main thread to continue while the operation is initializing.
Which one is recommended for waiting async methods inside main of a Console Application?
I would use a slightly modified version of the second approach. You can add a MainAsync method and call that from Main then you can use await inside it.
public static async Task MainAsync()
{
string result = await GetStringAsync();
Console.WriteLine(result);
}
public static int Main(string[] args)
{
MainAsync().Wait();
}
Also with console apps there is no risk of deadlock as there is no SynchronizationContext and the default thread pool one gets used.
The first approach continues execution after the asynch function is finished using a thread pool thread while the second approach continues execution using the calling thread that starts the asynch function.
With the second approach, there is a possibility of deadlocks. For example (similar to an example extracted from the book CLR via C#):
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
string result = getStringTask.Result; //the main thread is blocked waiting.
Console.WriteLine(result);
}
public Task<string> GetStringAsync()
{
// Issue the HTTP request and let the thread return from GetHttp
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/");
// We never get here: The main thread is waiting for this method to finish but this method
// can't finish because the main thread is waiting for it to finish --> DEADLOCK!
return await msg.Content.ReadAsStringAsync();
}
So the first approach avoids this problem:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
// We run on a thread pool thread
Task<string> getStringTask = GetStringAsync();
// We do get here because any thread pool thread can execute this code, we don't need the main thread.
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
Another solution is using ConfigureAwait(false), extracted from the book:
Passing true to this method gives you the same behavior as not calling
the method at all. But, if you pass false, the await operator does
not query the calling thread’s SynchronizationContext object and, when
a thread pool thread completes theTask, it simply completes it and the
code after the await operator executes via the thread pool thread.
public Task<string> GetStringAsync()
{
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/").ConfigureAwait(false);
// We DO get here now because a thread pool can execute this code
// as opposed to forcing the main thread to execute it.
return await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
}

c# async methods in asp.net mvc actions

Let's have the following situation
// method from class A
public async Task FooAsync()
{
return Task.Factory.StartNew(() => { //code_block_1 });
}
// method from class B
public async Task BarAsync()
{
return Task.Factory.StartNew(() => { //code_block_2 });
}
and an action method in a MVC controller
public async void SomeAction()
{
A a = new A();
B b = new B();
Task t1 = a.FooAsync();
Task t2 = b.BarAsync();
// Some other code 1
await Task.WhenAll(t1, t2);
// Some other code 2
}
And a request to that action is sent. How I think everything should work:
A thread from the thread pool will be assigned to process the request
The execution of SomeAction() starts in that thread. "a" and "b" are created.
FooAsync() is called. Task.Factory.StartNew() is executed which creates new task for "//code_block_1". From that moment it's up to the TaskScheduler what thread from the thread pool will process the task. It could be the same thread executing "SomeAction" (in that case the execution of FooAsync would be synchronous) or another thread from the pool.
BarAsync() is called. [Same as above]
"// Some other code 1" is executed on the same thread on which SomeAction() started.
await Task.WhenAll(t1, t2); creates a task which waits until both t1 and t2 have completed. Everything after the "await" ("// Some other code 2") is marked as "continuation" and the current thread is release back to the pool. Once both t1 and t2 have completed, the rest of the code can be processed by a thread from the pool (not necessarily the same thread which started processing SomeAction()).
And finally my question... Am I right? Am I wrong about something and what is it? And am I missing something?
Yes, this is almost entirely accurate.
It could be the same thread executing "SomeAction"
If that was the case there would be no point in calling StartNew. This method is meant to create parallelism. It never inlines the task. You probably confused this with Wait inlining unstarted tasks.
Note, that because of the parallelism you initiated request processing will block 2 threads instead of one. Hadn't you used await it would have taken 3.

Categories

Resources