question life time of an asynchronous thread...

  • Thread starter Thread starter Keyee Hsu
  • Start date Start date
K

Keyee Hsu

Hi, I have a C# app that creates an AppDomain, enters it, and spawns an
asyn thread to do some work and then block itself. Upon the completion
of the work, the async thread supposedly terminates, then the original
thread unblocks, unloads the AppDomain, and starts the whole process all
over again. I get the System.AppDomainUnloadedException saying that the
AppDomain from which the async thread resides has been unloaded. Now,
if I were to add a Thread.Sleep() command before the main thread returns
and unloads the AppDomain, then everything ran fine. I include the
program below hoping someone would shed some lights on this.

Thanks!


// program begins....

using System;
using System.Reflection;
using System.Threading;

namespace adSample
{
delegate void appDomainDelegate();

class asyncAD: MarshalByRefObject
{
private static AutoResetEvent evtWorkDone = new
AutoResetEvent(false);

[STAThread]
static void Main(string[] args)
{
try
{
for (int ix=0; ix<5; ++ix)
{
AppDomain AD =
AppDomain.CreateDomain("monitorAppDomain", null, null);
asyncAD ad = (asyncAD)AD.CreateInstanceAndUnwrap
(

Assembly.GetCallingAssembly().FullName,

"adSample.asyncAD"
);

ad.wrkStart();

Console.WriteLine("unloading AD\r\n");
AppDomain.Unload(AD);
} // for()
}
catch (AppDomainUnloadedException ex)
{
Console.WriteLine( "caught: {0}", ex.Message );
}

Console.WriteLine("Press Enter to quit the sample\r\n");
Console.ReadLine();
} // Main

//
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public void wrkStart()
{
appDomainDelegate dlgtAD = new
appDomainDelegate(wrkSpinoff);

/*
// case 1 ==================> OK
IAsyncResult iAR = dlgtAD.BeginInvoke(null,
null);
while (!iAR.IsCompleted)
{
Thread.Sleep(100);
} // while()

// Call EndInvoke to retrieve the results.
dlgtAD.EndInvoke(iAR);
*/

/*
// case 2 ==================> OK
IAsyncResult iAR = dlgtAD.BeginInvoke(null,
null);

// Call EndInvoke to retrieve the results.
dlgtAD.EndInvoke(iAR);
Thread.Sleep(1000);
*/

/*
// case 3 ==================>
System.AppDomainUnloadedException
IAsyncResult iAR = dlgtAD.BeginInvoke(null,
null);

// Call EndInvoke to retrieve the results.
dlgtAD.EndInvoke(iAR);
*/

/*
// case 4 ==================> OK
IAsyncResult iAR = dlgtAD.BeginInvoke(new
AsyncCallback(wrkCallback),

dlgtAD);

evtWorkDone.WaitOne();
Thread.Sleep(1000);
*/

/*
*/
// case 5 ==================>
System.AppDomainUnloadedException
IAsyncResult iAR = dlgtAD.BeginInvoke(new
AsyncCallback(wrkCallback),

dlgtAD);

evtWorkDone.WaitOne();

Console.WriteLine("exiting from: {0}",
Thread.GetDomain().FriendlyName);
} // wrkStart()

//
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public void wrkSpinoff()
{
Console.WriteLine("in wrkSpinoff()");

for (int ix=0; ix<5; ++ix)
{
Console.WriteLine(ix);
Thread.Sleep(500);
} // for(ix)

Console.WriteLine("exiting wrkSpinoff()");
} // wrkSpinof()

//
-------------------------------------------------------------------
private void wrkCallback(IAsyncResult ar)
{
Console.WriteLine("in wrkCallback()");
appDomainDelegate dlgt = (appDomainDelegate)ar.AsyncState;

dlgt.EndInvoke(ar);

Console.WriteLine("exiting wrkCallback()");
evtWorkDone.Set();
} // wrkCallback()

} //asyncAD
} // adSample
 
I was able to run through 20 plus iterations without a crash by modifieing
your wrkCallBack method:

private void wrkCallback(IAsyncResult ar)
{
Console.WriteLine("in wrkCallback()");
appDomainDelegate dlgt = (appDomainDelegate)ar.AsyncState;

evtWorkDone.Set();
dlgt.EndInvoke(ar);

Console.WriteLine("exiting wrkCallback()");

} // wrkCallback()

Before your were calling EndInvoke then Set, what I believe was happening
(I'm not up to par yet on some aspects of threading) is that you were
calling EndEnvoke which released your WaitOne in wrkStart, then calling Set
trying to signal the tread (at which point, wrkStart had exited, and maybe
even tried to unload the AppDomain). So random mayem resulted.

Let me know if that fixes it,

Tim

Keyee Hsu said:
Hi, I have a C# app that creates an AppDomain, enters it, and spawns an
asyn thread to do some work and then block itself. Upon the completion
of the work, the async thread supposedly terminates, then the original
thread unblocks, unloads the AppDomain, and starts the whole process all
over again. I get the System.AppDomainUnloadedException saying that the
AppDomain from which the async thread resides has been unloaded. Now,
if I were to add a Thread.Sleep() command before the main thread returns
and unloads the AppDomain, then everything ran fine. I include the
program below hoping someone would shed some lights on this.

Thanks!


// program begins....

using System;
using System.Reflection;
using System.Threading;

namespace adSample
{
delegate void appDomainDelegate();

class asyncAD: MarshalByRefObject
{
private static AutoResetEvent evtWorkDone = new
AutoResetEvent(false);

[STAThread]
static void Main(string[] args)
{
try
{
for (int ix=0; ix<5; ++ix)
{
AppDomain AD =
AppDomain.CreateDomain("monitorAppDomain", null, null);
asyncAD ad = (asyncAD)AD.CreateInstanceAndUnwrap
(

Assembly.GetCallingAssembly().FullName,

"adSample.asyncAD"
);

ad.wrkStart();

Console.WriteLine("unloading AD\r\n");
AppDomain.Unload(AD);
} // for()
}
catch (AppDomainUnloadedException ex)
{
Console.WriteLine( "caught: {0}", ex.Message );
}

Console.WriteLine("Press Enter to quit the sample\r\n");
Console.ReadLine();
} // Main

//
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public void wrkStart()
{
appDomainDelegate dlgtAD = new
appDomainDelegate(wrkSpinoff);

/*
// case 1 ==================> OK
IAsyncResult iAR = dlgtAD.BeginInvoke(null,
null);
while (!iAR.IsCompleted)
{
Thread.Sleep(100);
} // while()

// Call EndInvoke to retrieve the results.
dlgtAD.EndInvoke(iAR);
*/

/*
// case 2 ==================> OK
IAsyncResult iAR = dlgtAD.BeginInvoke(null,
null);

// Call EndInvoke to retrieve the results.
dlgtAD.EndInvoke(iAR);
Thread.Sleep(1000);
*/

/*
// case 3 ==================>
System.AppDomainUnloadedException
IAsyncResult iAR = dlgtAD.BeginInvoke(null,
null);

// Call EndInvoke to retrieve the results.
dlgtAD.EndInvoke(iAR);
*/

/*
// case 4 ==================> OK
IAsyncResult iAR = dlgtAD.BeginInvoke(new
AsyncCallback(wrkCallback),

dlgtAD);

evtWorkDone.WaitOne();
Thread.Sleep(1000);
*/

/*
*/
// case 5 ==================>
System.AppDomainUnloadedException
IAsyncResult iAR = dlgtAD.BeginInvoke(new
AsyncCallback(wrkCallback),

dlgtAD);

evtWorkDone.WaitOne();

Console.WriteLine("exiting from: {0}",
Thread.GetDomain().FriendlyName);
} // wrkStart()

//
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public void wrkSpinoff()
{
Console.WriteLine("in wrkSpinoff()");

for (int ix=0; ix<5; ++ix)
{
Console.WriteLine(ix);
Thread.Sleep(500);
} // for(ix)

Console.WriteLine("exiting wrkSpinoff()");
} // wrkSpinof()

//
-------------------------------------------------------------------
private void wrkCallback(IAsyncResult ar)
{
Console.WriteLine("in wrkCallback()");
appDomainDelegate dlgt = (appDomainDelegate)ar.AsyncState;

dlgt.EndInvoke(ar);

Console.WriteLine("exiting wrkCallback()");
evtWorkDone.Set();
} // wrkCallback()

} //asyncAD
} // adSample
 
Thanks, Tim, yes that seems to fix the problem for case #5. A couple of
things with this scenario, though. One, case #3 still fails without the
callback being used. Second, for case #5, the main thread in wrkStart()
does not continue until the event is set (EndInvoke() itself doesn't
unblock the main thread), so by setting the event before the the
EndInvoke() call in wrkCallback(), it should have caused the main thread
to unblock even sooner and thus unloads the AppDomain even earlier.
Which, I think, should've made the problem worse, not fixing it like it
did. So, I'm even more perplexed now as to what happened behind the
scenes 8-(. What do you think?
 
Back
Top