.NET Processes | Threads | Application Domains | Contexts & Their Relationships Exposed

I have been asked many times about the relationships between Processes, Application Domains (AppDomains) and Threads. Lets explore today various aspects of these objects along with their functionalities  in context to .NET framework.

Quality means doing it right when no one is looking.
Henry Ford

Quality providers are actually background workers and are invisible, always!  
Some Worker

Before going into the details, let me go through the Process in computing itself. A Process is actually an instance of an application that is loaded + executed in the memory by the OS (Operating System) on demand. Or in other terms when you run an application, the OS creates/loads it into a separate and isolated memory that is composed of at least three regions, Code Segment, Data Segments and Stack Segment and OS ensures of no overlapping among them, as well as also are protected from other processes (complete isolation). The code instructions are loaded in the code segment while all the global variables, objects, etc. are loaded in the data segment. This segment has also a space for heap, that used to be managed by the user in older days (C, C++ or un-managed applications) where as in recent OS’s like .NET it is managed by the garbage collector (GC) that is actually part of the .NET framework (more on it later) . Stack is used for local variables created in a function as well as return address of execution of the method/function. Code Segment is a read only/protected memory while Data Segment & Stack are read-write memory regions. In context to .NET, System.Diagnostics.Process abstracts away the Process details and provides handy utilities to get information about the Processes in the .NET driven applications. 

Now the obvious question is what is a Thread. Well I can only say “good question”, lets move on. Ok, Ok, If you really insist   A thread is merely a reusable path of execution per unit time slice of a processor or if its a multiprocessor that has exactly same processors as threads, then the execution is per processor. In a multithreading applications you could have more than one separate execution paths where some are managed by the application itself and some are spawned by the application developers as needed. When you run the application, the process creates a main/primary thread of execution that is actually an entry point for an application, like in WPF it is the Application.Run(.) or in console applications is the Main(.) method. As needed further threads are spawned by this primary thread also known as worker threads. That is why if you look at the framework, System.Threading.Thread is responsible for creating threads not the System.Diagnostics.Process.  All threads of a process share its virtual address space or they share a common heap memory (like the static and global variables are shared) . They are also provided with “Thread Local Storage (TLS)” [Wicki] and private call stack. Read more about these concepts here [msdn].

You may ask, why we use multithreading model instead of single threaded one? Well, because, the real world applications are distributed / multithreaded.   No one person can do each and every thing in this world/universe all alone. There is a team work involved for a big achievement. The work load has to be divided among specialized people / threads to get the ultimate job done. Like wise computer programs are no different. If you give a responsibility of every thing to the Primary thread then you’ll see that application will be sluggish, some times non-responsive that you might need to move on to a coffee thread . So for responsiveness, for quality work like long mathematical calculations / specialized real world needs you go for multithreaded / multiprocessor based applications.

Here is a minimal example of how we spawn a worker thread, i hope you don't like it . For more intuitive example, please take a look at my earlier post on blocking queues, here is the link for it. [Blocking Queues]

Code Snippet
  1. public class Test1
  2.     {
  3.         public static void RunCounter()
  4.         {
  5.             System.Diagnostics.Debug.WriteLine("Entering Main thread | " +
  6.                 Thread.CurrentThread.GetHashCode().ToString());
  8.             // Create a worker thread
  9.             Thread workerThread = new Thread(delegate()
  10.             {
  11.                 System.Diagnostics.Debug.WriteLine("Entering workerThread, Hash is| " + Thread.CurrentThread.GetHashCode().ToString());
  13.                 for (int i = 0; i < 11; i++)
  14.                 {
  15.                     System.Diagnostics.Debug.WriteLine(string.Format("Worker Thread counter: {0}", i));
  16.                     Thread.Sleep(500);
  17.                 }
  18.             });
  19.             workerThread.Start();
  21.             // we are still in the main/primary thread
  22.             System.Diagnostics.Debug.WriteLine("Entering Again Main thread, Hash is | " +
  23.                 Thread.CurrentThread.GetHashCode().ToString());
  25.             for (int i = 0; i < 7; i++)
  26.             {
  27.                 System.Diagnostics.Debug.WriteLine(string.Format("Main thread counter : {0}", i));
  29.                 Thread.Sleep(1000);
  30.             }
  32.             System.Diagnostics.Debug.WriteLine("--- Main thread, work done ---");
  33.         }
  35.         /* Output :>
  36.             Entering Main thread | 10
  37.             Entering Again Main thread, Hash is | 10
  38.             Entering workerThread, Hash is| 3
  39.             Worker Thread counter: 0
  40.             Main thread counter : 0
  41.             Worker Thread counter: 1
  42.             Worker Thread counter: 2
  43.             Main thread counter : 1
  44.             Worker Thread counter: 3
  45.             Worker Thread counter: 4
  46.             Main thread counter : 2
  47.             Worker Thread counter: 5
  48.             Worker Thread counter: 6
  49.             Main thread counter : 3
  50.             Worker Thread counter: 7
  51.             Worker Thread counter: 8
  52.             Main thread counter : 4
  53.             Worker Thread counter: 9
  54.             Worker Thread counter: 10
  55.             Main thread counter : 5
  56.             The thread '<No Name>' (0x2bfc) has exited with code 0 (0x0).
  57.             Main thread counter : 6
  58.             --- Main thread, work done ---
  59.          * */
  60.     }


Now lets move on to .NET Application Domains or simply AppDomains. AppDomains are actually a subdivision or logical partition within Process in order to host .NET executables/assemblies. A process can have or can host one or more AppDomains as shown in the figure below (Figure-1). And an AppDomain can have one (+1) or more (+*) Contexts or Context Boundaries (I’ll come to this a little later).

Process Figure-1

ClassDiagram02 Figure-2

So now the question is why we need AppDomains. As you know when you run a .NET application it is managed by a OS/platform independent runtime known as Common Language Runtime (CLR). and the CLR gets this independency with the help of AppDomains and the class that is responsible for this job is System.AppDomain (Figure-2 above). AppDomains are like a light-weight process in terms of memory and processing requirements and they can be unloaded or loaded on-demand by the process or by the developer as needed.  Like the primary thread was created by the Process, the CLR automatically creates a default or primary AppDomain and hosts your application right away. Further AppDomains can be created by calling AppDomain.CreateDomain(.) static factory method. If you have more than one AppDomain, these AppDomains are isolated from each other and when they need to send information among each other, the information (like heap data) needs to be marshaled and that’s why it is derived from MarshalByRefObject or in simple terms the AppDomains are remotable objects (Look for C# Remoting for MarshalByRefObject).  The interesting methods in the AppDomain class are encircled above (Figure-2).

ClassDiagram03 Figure-3

Last but not least the “Contexts”; As mentioned earlier A process is composed/subdivided into 1-n AppDomains likewise AppDomains are composed of one to many Contexts or Context Boundaries. The context provides a special purpose boundary around an object, if adorned with a ContextAttribute. Like, if you look at the Figure-3, SynchronizationAttribute, if adorned on an object, the whole object will become thread-safe.  Also, like default AppDomain, the AppDomain creates a default context known as “context-0”. It is the first context where the objects resides who don't have special needs and these regular objects, loaded in some application domain, are also known as Context-Agile objects. Here is an example of a special need object, that needs synchronization or inherent thread-safety provided by CLR running for WPF applications.

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  6. using System.Runtime.Remoting.Contexts;
  7. using System.Threading;
  9. namespace WpfTestApp
  10. {
  11.     // SynchronizationAttribute Enforces a synchronization domain for the
  12.     // current context and all contexts that share the same instance.
  13.     // Any object loaded in this context is thread-safe.
  14.     //
  15.     [Synchronization]
  16.     class SyncContextBoundObject : ContextBoundObject
  17.     {
  18.         public SyncContextBoundObject() {}
  20.         public void ShowContextInfo()
  21.         {
  22.             // Display Current AppDomain Info
  23.             System.Diagnostics.Debug.WriteLine("AppDomain Id | " + AppDomain.CurrentDomain.Id.ToString());
  24.             System.Diagnostics.Debug.WriteLine("AppDomain FriendlyName | " + AppDomain.CurrentDomain.FriendlyName);
  26.             // Display Current Thread Info
  27.             System.Diagnostics.Debug.WriteLine("Thread FriendlyName | " + Thread.CurrentThread.Name);
  28.             System.Diagnostics.Debug.WriteLine("Thread HashCode | " + Thread.CurrentThread.GetHashCode().ToString());
  30.             // Display Current Context Info
  31.             System.Diagnostics.Debug.WriteLine("Context ID | " + Thread.CurrentContext.ContextID);
  32.             System.Diagnostics.Debug.WriteLine("Thread HashCode | " + Thread.CurrentContext.GetHashCode().ToString());
  34.             // Display Context Properties...
  35.             foreach (IContextProperty contextProperty in Thread.CurrentContext.ContextProperties)
  36.             {
  37.                 System.Diagnostics.Debug.WriteLine("Context Property[.] | " + contextProperty.Name);
  38.             }
  40.         }
  42.         public void ShowPrimesUsingLinq(int n)
  43.         {
  44.             Func<int, IEnumerable<int>> primeNumbersExpr = (x) =>
  45.                  from i in Enumerable.Range(2, x - 1)
  46.                     where Enumerable.Range(2, i - 2).All(j => i % j != 0)
  47.                         select i;
  49.             var resultSet = primeNumbersExpr(n);
  51.             foreach (int i in resultSet)
  52.             {
  53.                 System.Diagnostics.Debug.WriteLine(i);
  54.             }
  55.         }
  56.     }
  58.     public class Test2
  59.     {
  60.         public static void RunSyncContext()
  61.         {
  62.             SyncContextBoundObject syncObject = new SyncContextBoundObject();
  63.             syncObject.ShowContextInfo();
  64.             /* Output :>            
  65.                     AppDomain Id | 1
  66.                     AppDomain FriendlyName | WpfTestApp.vshost.exe
  67.                     Thread FriendlyName |
  68.                     Thread HashCode | 10
  69.                     Context ID | 1
  70.                     Context Property[.] | LeaseLifeTimeServiceProperty
  71.                     Context Property[.] | Synchronization
  72.             */
  73.             syncObject.ShowPrimesUsingLinq(11);
  74.         }
  75.     }
  76. }

One more thing that is important and quite notable is that although, their is no direct coherence between AppDomains and Threads (Figure-1) but a particular thread when activated is attached to One particular AppDomain. Or in other words, like AppDomains, the threads are not restricted to one domain, rather they are free to move around in different AppDomains, the only restriction is, a thread cannot be present in two different locations/domains at one time.

That's all for now folks, will talk to you more on threading next time. I’ll be looking forward to your feedbacks/comments, enjoy


If you enjoyed reading this blog, leave your valuable feedback and consider subscribing to the RSS feed. You can also subscribe to it by email. Also, you can follow me on Twitter. Thank you!


STD Testing Near Me Denver
3/14/2018 9:22:48 PM #

Testing for STDs with often takes 5 minutes.

STD Testing Near Me Nashville
3/15/2018 1:40:09 AM #

On the lookout for HIV testing sites apart from the Borum?

STD Testing Center Near Me
3/15/2018 5:16:36 AM #

Most STDs show no symptoms at all.

STD Testing Facilities Near Me
3/15/2018 5:55:57 PM #

Our STD testing is free and completely confidential.

forex trading signal
3/16/2018 12:17:43 AM #

I loved as much as you will receive carried out right here. The sketch is tasteful, your authored material stylish. nonetheless, you command get bought an shakiness over that you wish be delivering the following. unwell unquestionably come more formerly again since exactly the same nearly a lot often inside case you shield this increase.  Look at my web-site  forex trading signal - www.montreal-real-estate.com/.../REFERRER.html

hooked on phonics
3/18/2018 4:42:08 AM #

Hello There. I found your weblog the usage of msn. That is an extremely neatly written article. I will be sure to bookmark it and come back to read more of your helpful information. Thanks for the post. I'll certainly return.

заказать диплом
3/19/2018 12:00:51 PM #

Hello, I want to subscribe for this web site to get latest updates, therefore where can i do it please help out.

seks daten
3/19/2018 8:21:51 PM #

Nou Gratis neuken is hier ook echt gratis neuken!

I'm now not positive the place you're getting your information, but good topic. I needs to spend a while studying much more or figuring out more. Thanks for magnificent info I used to be searching for this information for my mission.

Hi to every , for the reason that I am in fact keen of reading this webpage's post to be updated daily. It consists of good information.

Thank you for another informative web site. Where else may I get that type of info written in such a perfect manner? I have a project that I am simply now running on, and I've been at the look out for such information.

Hey very interesting blog!

Add comment