Abstract
In this article, you"ll drill deeper into the details of how an assembly is hosted by the CLR and will understand the relationship among Application Domains (appdomain) and processes. An appdomain in a nutshell is a segment within a given process that hosts a set of related .NET assemblies. In addition to that, this article also explores manipulation with currently running processes.
Process
A process is a fixed, safe boundary for a running program and operating system level concept used to describe a set of resources and the necessary memory allocations used by a running application. The operating creates a separate and isolated process for each executable loaded into memory. Furthermore, in application isolation, the result is much more stable and robust in the runtime environment because the failure of one process does not affect the functioning of another process. Data in one process can't be directly accessed by another process unless you use a distributed API programming such as WCF, COM+, and Remoting.
Every Windows process is assigned a unique process identifier (PID) and may be independently loaded and unloaded by the OS. You can view the various running processes of the Windows OS using the Task Manager as in the following:
Every Windows process contains an initial thread that is the entry point (from Windows) for the application. Formally speaking, a thread is a path of execution within a process. Processes that contain a single primary thread of execution are considered to be thread-safe.
Process in Depth
The System.Diagonostic namespace defines a number of types that allow you to programmatically interact with processes and various other manipulations such as Performance Counters and event logs.

To illustrate the process of manipulating a Process object, assume you have a console application that displays all the currently running processes in the system.
- using System;
- using System.Diagnostics;
- namespace ProcessDemo
- {
- class Program
- {
- static void Main(string[] args)
- {
- Process[] p = Process.GetProcesses("system-machine");
- foreach (Process a in p)
- {
- Console.WriteLine("Current Running Processes\n");
- string str = string.Format("PID::{0} \t Name::{1}",a.Id,a.ProcessName);
- Console.WriteLine(str);
- Console.ReadKey();
- }
- }
- }
- }

- using System;
- using System.Diagnostics;
- namespace ProcessDemo
- {
- class Program
- {
- static void Main(string[] args)
- {
- Console.Write("Enter Process ID::");
- string pid = Console.ReadLine();
- Process p = null;
- try
- {
- p = Process.GetProcessById(int.Parse(pid));
- }
- catch(Exception)
- {
- Console.WriteLine("PID not Found");
- }
- Console.WriteLine("Threds used by: {0}",p.ProcessName);
- ProcessThreadCollection ptc = p.Threads;
- foreach (ProcessThread a in ptc)
- {
- Console.WriteLine("Current Running Processes\n");
- string str = string.Format("PID::{0} \t Start Time::{1}",a.Id,a.StartTime.ToShortTimeString());
- Console.WriteLine(str);
- Console.ReadKey();
- }
- }
- }
- }
When you run your company, you can now enter the PID of any process on your machine and threads used in the process as in the following:

- using System;
- using System.Diagnostics;
- namespace ProcessDemo
- {
- class Program
- {
- static void Main(string[] args)
- {
- Process p = null;
- try
- {
- p = Process.Start("chrome.exe","www.google.com");
- }
- catch(Exception)
- {
- Console.WriteLine("Error!!!");
- }
- Console.WriteLine("Process Start: {0}",p.ProcessName);
- Console.ReadKey();
- }
- }
- }
- An AppDomain can be independently securedWhen an appdomain is created, it can have a permission set applied to it that determines the maximum rights granted to the assemblies running in the AppDomain that ensures the code cannot be corrupted.
- An AppDomain can be unloadedThe CLR doesn't endorse the ability to unload a single assembly from an AppDomain. However, the CLR will notify to unload the entire currently contained assemblies from an appdomain.
- Independently configuredAn AppDomain can have a cluster of configuration settings associated with it, for instance how the CLR loads assemblies into the appdomain, searches the path, and does loader optimization.
- No mutual intervention by multiple appdomainsWhen code in an AppDomain creates an object, it is not allowed to live beyond the lifetime of the AppDomain. The code in another AppDomain can access another object only by Marshal by reference or Marshal by value. This enforces a clean separation because code in one appdomain can't have a direct reference to an object created by another code in a different appdomain.
- PerformanceApplication Domains are less expensive thus the CLR is able to load and unload an Application Domain much faster than a formal process and that improves the performance.
The following image shows a single Windows process that has one CLR COM server running in it. This CLR is currently managing two Application Domains. Each appdomain has its own Heap and has a record of which type has been accessed since the appdomain was created. Apart from that, each Application Domain has some Assemblies loaded into it. AppDomain #1 (the default) has three assemblies and AppDomain #2 has two assemblies loaded: xyz.dll and System.dll.
So the entire purpose of An Application Domain is to provide isolation. The CLR needs to be able to unload an appdomain and free up all of its resources without adversely affecting any other appdomain.

| Methods | Description |
| CreateDomain() | It allows us to create a new Application Domain. |
| CreateInstance() | Creates an instance of the type in an external assembly. |
| ExecuteAssembly() | It executes a *.exe assembly in the Application Domain. |
| Load() | This method dynamically loads an assembly into the current app domain. |
| UnLoad() | It allows us to unload a specified AppDomain within a given process. |
| GetCurrentThread() | Returns the ID of the active thread in the current Application Domain. |
In addition, the AppDomain class also defines a set of properties that can be useful when you wish to monitor the activity of a given Application Domain.
| Properties | Description |
| CurrentDomain | Gets the Application Domain for the currently executing thread. |
| FriendlyName | Gets the friendly name of the current Application Domain. |
| SetupInformation | Get the configuration details for a given Application Domain. |
| BaseDirectory | Gets the directory path that the assembly resolver uses to probe for assemblies. |
The following sample shows that a created assembly is called from another Application Domain. So, first, create a console application AppDomainTest. In the main() add a Console.WriteLine() so that you can see when this method is called.
- using System;
- namespace AppDomainTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- // Main assembly that is called from another AppDomain
- Console.WriteLine("AppDomainTest in new created Domain '{0}' called"
- , AppDomain.CurrentDomain.FriendlyName);
- Console.WriteLine("ID of the Domain '{0}'"
- , AppDomain.CurrentDomain.Id);
- Console.ReadKey();
- }
- }
- }
- Using System;
- //add a reference to AppDoaminTest.exe
- namespace DemoTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- AppDomain d1 = AppDomain.CurrentDomain;
- Console.WriteLine(d1.FriendlyName);
- AppDomain d2 = AppDomain.CreateDomain("New AppDomain");
- d2.ExecuteAssembly("AppDomainTest.exe");
- }
- }
- }
When you compile the DemoTest project, first the Current domain friendly name will be displayed followed by the called assembly as in the following:

- using System;
- using System.IO;
- using System.Linq;
- namespace DemoTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- AppDomain newDomain = AppDomain.CreateDomain("New AppDomain");
- try
- {
- newDomain.Load("TestLib");
- }
- catch (FileNotFoundException)
- {
- Console.WriteLine("Not Found");
- }
- ListAssemblies(newDomain);
- Console.ReadKey();
- }
- static void ListAssemblies(AppDomain ad)
- {
- var la = from a in ad.GetAssemblies()
- orderby a.GetName().Name
- select a;
- Console.WriteLine("Assemblies Loaded {0}\n",ad.FriendlyName);
- foreach(var a in la)
- {
- Console.WriteLine("Name:: {0}:", a.GetName().Name);
- Console.WriteLine("Version:: {0}:\n", a.GetName().Version);
- }
- }
- }
- }
This time the output of the previous program is as in the following:


Dennis ThomasPosted Dec 21, 2017, 4:43 AM
Thank you for the article! Well explained.
Sam HobbsPosted Feb 11, 2015, 12:50 AM
Actually thread safety is determined by the ability of a thread to access shared data structures in a manner that guarantees safe execution by multiple threads. The term safe and safety in this context usually refers to objects a thread might use, not the thread itself. Generally a thread could be called thread-safe if all the objects it uses that are not in its stack (its stack is automatically thread-safe) are thread-safe and/or used in a thread-safe manner (such as with synchronization).
Suraj SahooPosted Feb 11, 2015, 12:44 AM
This is great. Thanks Sir :)