Question on AppDomain and Thread

G

Guest

Hi,

When you create a new AppDomain, objects you created in there using say
AppDomain.CreateInstanctAndUnwrap() run in the same thread as the caller is
that correct?

If so, how could I create an AppDomain having its distinct thread? In
particularly, I would like to create several AppDomains each with its own STA
so that I can have UI object living in them and they are running concurrently.

Kind of like transplanting an unmanaged architecture involving several ole
automation servers (executables with their independent threads) to managed
world using one executables but they are mapped to AppDomain partitioning.
But each AppDomain must have its own thread with its own message pump so that
WinForm objects can live there.

Thanks.

Leon
 
D

Dave Sexton

Hi Leon,
When you create a new AppDomain, objects you created in there using say
AppDomain.CreateInstanctAndUnwrap() run in the same thread as the caller
is
that correct?

When you invoke a method on the object it will be invoked on the current
thread in the AppDomain in which the object was created.
If so, how could I create an AppDomain having its distinct thread? In
particularly, I would like to create several AppDomains each with its own
STA
so that I can have UI object living in them and they are running
concurrently.

AppDomains don't own threads. They are shared amongst all AppDomains in the
process, but a single thread will only execute in one AppDomain at a time.

To execute code concurrently and within a different AppDomain, create a
background thread to invoke an object's method or provide asynchronous
methods on your object (preferred). If the object is a MarshalByRefObject
obtained from a different AppDomain then the code will execute within that
AppDomain, concurrently with the main thread of your application, when
calling on a background thread just as it would an object within the same
AppDomain as the caller.
Kind of like transplanting an unmanaged architecture involving several ole
automation servers (executables with their independent threads) to managed
world using one executables but they are mapped to AppDomain partitioning.
But each AppDomain must have its own thread with its own message pump so
that
WinForm objects can live there.

I'm not sure what value there would be in managing multiple interface
components in multiple AppDomains, but I don't think it's possible anyway.
Controls can only be manipulate on the thread in which they were created.
Therefore, you may be able to have Forms within different AppDomains running
simultaneously, but I doubt that you'll be able to make them children of the
same MDI container, and you won't be able to have controls from different
AppDomains on the same Form. If you were intending to do drag & drop
operations between different Forms, for example, that wouldn't work either
unless the control was recreated in the target AppDomain's thread.

Normally, an application has just one GUI thread and invokes long-running
processes on background threads. If the long-running processes need
isolation from the default AppDomain then you can execute them within a
separate AppDomain, asynchronously, but all GUI components should be created
on the same thread (the one that started the message loop with a call to
Application.Run).
 
J

Jon Shemitz

Dave said:
I'm not sure what value there would be in managing multiple interface
components in multiple AppDomains,

Probably mostly memory consumption. Running multiple apps in separate
AppDomains of a single process means that they share all the CLR
machinery, not just its code pages; they share a single
garbage-collected heap; they share a single string interning table;
there's only one set of metadata loaded for each common library;
there's none of the OS overhead involved in creating and running
multiple processes.

Secondarily, startup time might be lower for the 'other' apps, as much
of their code will already be loaded.
 
D

Dave Sexton

Hi Jon,

Thanks for your reply.

You make an interesting point, but there is an added overhead of having to
marshal calls between the AppDomains through a transparent proxy that uses
the remoting framework's messaging system. I'm not sure it's worth it if
the OP will be invoking methods across AppDomain boundaries. There seems to
be a trade-off between memory consumption and performance here that the OP
would have to make, considering also that there is no requirement to
aggregate the GUI components from multiple threads into a single GUI, which
is not possible in WinForms.
 
G

Guest

Thanks Dave for your reply. My comments below.

:

I'm not sure what value there would be in managing multiple interface
components in multiple AppDomains, but I don't think it's possible anyway.
Controls can only be manipulate on the thread in which they were created.
Therefore, you may be able to have Forms within different AppDomains running
simultaneously, but I doubt that you'll be able to make them children of the
same MDI container, and you won't be able to have controls from different
AppDomains on the same Form. If you were intending to do drag & drop
operations between different Forms, for example, that wouldn't work either
unless the control was recreated in the target AppDomain's thread.

Normally, an application has just one GUI thread and invokes long-running
processes on background threads. If the long-running processes need
isolation from the default AppDomain then you can execute them within a
separate AppDomain, asynchronously, but all GUI components should be created
on the same thread (the one that started the message loop with a call to
Application.Run).
I probably did not make it very clear. Objects in this AppDomain,
particularly UI objects like controls are not required to marshal across the
AppDomain boundary. While crossing AppDomain WinForm operation is
problematics, it is not forebidden nor not possible. It only means you cannot
marshal Control-derived objects across.

Because these AppDomain contains essentially autonomous 'program-let', they
can run by themselves. All they need to survive is a message pump and STA.

Putting these 'program-let' in its AppDomain without its own thread prevents
the manager (aka Windows Explorer) from terminating them should they become
stuck.

Drag-Drop is not considered.

One possible way to give each AppDomain its own STA Thread is to have a
client side component that manages this AppDomain's lifetime as well as its
thread. My idea is then to create this AppDomain in a thread's ThreadStart
(the thread proc). Since this component starts the Thread, it can define the
ApartmentState prior to starting the thread.

However, I am at a loss of how to maintain a message loop inside this thread
proc (in managed code) to dispatch messages for windows objects created in
this thread. In unmanaged world, this is simply a MsgWaitForMultipleObjects()
or GetMessage() followed by TranslateMessage/DispatchMessage().

In the Main, one has Application.Run() while is essentially the unmanaged
world's GetMessage() loop.

How do you do similar thing in .Net/Managed code?

Transplanting a design involving multiple applications into multi-AppDomains
has many benefits as some other readers have commented. One particularly one
is that .Net BCL does not have application lifecycle management framework
that COM has. Using .Net Remoting often is a struggle with starting and
terminating server in this usage as .Net Remoting assumes the server is
already running and never die.

Leon
 
D

Dave Sexton

Hi Leon,

However, I am at a loss of how to maintain a message loop inside this
thread
proc (in managed code) to dispatch messages for windows objects created in
this thread. In unmanaged world, this is simply a
MsgWaitForMultipleObjects()
or GetMessage() followed by TranslateMessage/DispatchMessage().

In the Main, one has Application.Run() while is essentially the unmanaged
world's GetMessage() loop.

How do you do similar thing in .Net/Managed code?

I tried creating a test program that called Application.Run on two separate
threads, concurrently, each executing in separate AppDomains and both
startup Forms were visible and interactive. The Application.MessageLoop
property returned true in both threads.

1. Define a class that derives from MarshalByRefObject
2. Add a method such as the following:

public EventWaitHandle RunAsync()
{
EventWaitHandle closedEvent = new EventWaitHandle(false,
EventResetMode.AutoReset);

Thread thread = new Thread(delegate() // 2.0 anonymous method
{
// the following line will block until Form is closed
System.Windows.Forms.Application.Run(new Form());

closedEvent.Set();
});

thread .SetApartmentState(ApartmentState.STA);
thread .Start();

return closedEvent;
}

3. When your application starts create a new AppDomain
4. Create a new instance of your MarshalByRefObject in the new AppDomain
by calling CreateInstanceAndUnwrap
5. Call the RunAsync method.
Transplanting a design involving multiple applications into
multi-AppDomains
has many benefits as some other readers have commented. One particularly
one
is that .Net BCL does not have application lifecycle management framework
that COM has. Using .Net Remoting often is a struggle with starting and
terminating server in this usage as .Net Remoting assumes the server is
already running and never die.

When calling between AppDomains you're still using the remoting framework,
however, so the same assumptions are still made. An
AppDomainUnloadedException is thrown in the case that a proxy becomes
unusable because the AppDomain in which its target was created has been
unloaded, although that's much better, IMO, than the generic
RemotingException that would be thrown in a similar, cross-process
circumstance.
 
G

Guest

Thanks Dave for that great suggestion.

When calling between AppDomains you're still using the remoting framework,
however, so the same assumptions are still made. An
AppDomainUnloadedException is thrown in the case that a proxy becomes
unusable because the AppDomain in which its target was created has been
unloaded, although that's much better, IMO, than the generic
RemotingException that would be thrown in a similar, cross-process
circumstance.
I am at a loss to understand what you mean here? I realise crossing
AppDomain would involve the remoting framework. That's fine because there is
extremely little traffic crossing that AppDomain and I can bear with that.

When did you get the AppDomainUnloadedException? Is that when you unload the
AppDomain while the forms are still running?

Thanks again.
 
D

Dave Sexton

Hi Leon,

An AppDomainUnloadedException will be thrown when code attempts an
invocation on a proxy that is no longer valid because the AppDomain in which
its target was created has been unloaded. e.g., create and unwrap a
MarshalByRefObject from another AppDomain, creating a transparent proxy in
the calling AppDomain, then unload the AppDomain in which the proxy's target
was created and try to invoke a method.

The point is that a cross-process call, where the proxy is no longer valid,
results in a RemotingException (for Ipc, SocketException for Tcp or
WebException for Http), which is quite ambiguous.
AppDomainUnloadedException, to the contrary, is quite clear.
 
C

Cordell Lawrence \(News Group\)

Hi Leon,
Check out AppDomain.DoCallback() and documentation for the call and the
CrossAppDomainDelegate . Haven't read through the discussion fully, but this
may help. Don Box in Essential.NET advises that you use static methods for
the callbacks themselves.

Cordell Lawrence
Teleios Systems Ltd.
 
G

Guest

Dave Sexton said:
Hi Leon,

An AppDomainUnloadedException will be thrown when code attempts an
invocation on a proxy that is no longer valid because the AppDomain in which
its target was created has been unloaded. e.g., create and unwrap a
MarshalByRefObject from another AppDomain, creating a transparent proxy in
the calling AppDomain, then unload the AppDomain in which the proxy's target
was created and try to invoke a method.

The point is that a cross-process call, where the proxy is no longer valid,
results in a RemotingException (for Ipc, SocketException for Tcp or
WebException for Http), which is quite ambiguous.
AppDomainUnloadedException, to the contrary, is quite clear.
So as long as I am aware that the AppDomain is unloaded and to clean out the
proxy prior to unloading, I should be fine. Right.

Leon
 
D

Dave Sexton

Hi Leon,

Right :)

--
Dave Sexton

Leon said:
So as long as I am aware that the AppDomain is unloaded and to clean out
the
proxy prior to unloading, I should be fine. Right.

Leon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top