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 newAppDomain
- invoke
Do
method passingMarshalableCompletionSource
in order later to know whenasync
Do
method is completed. - Once
Do
method is completed, trying toUnload
theAppDomain
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?