The series so far:
- The Unconventional Guide to Introduction to Thread
- Why Do People Think Dedicated CLR Threads is a Good Idea?
- How Not Knowing Thread Members and Execution State Makes You a Rookie
- Doing Thread Scheduling and Priority the Right Way
- How to Start Using CLR's Thread Pool
- What Wikipedia Can't Tell You About Thread Execution Contexts
- The Insider's Guide to Cooperative Cancellation and Timeout
Introduction
Every Thread has an execution context data structure associated with it.
The ExecutionContext class provides a single container for all information relevant to a logical thread of execution. This class includes Security context, Call context, and Synchronisation context.
Please refer to the below table.
Security Settings | Compressed Stack | Windows Identity | Thread’s Principal |
---|---|---|---|
Host Settings | Host Execution Context Manager | ||
Logical Call Context Data | System.Runtime.Remoting.Messaging.CallContext.LogicalSetData System.Runtime.Remoting.Messaging.CallContext.LogicalGetData |
Note: The common language runtime ensures that the ExecutionContext is consistently transferred across runtime-defined asynchronous points within the managed process.
Usage
Let us examine the default Behavior between a Thread and a Helper Thread. Whenever Thread uses another Thread to perform tasks:
- Execution Context flows to the helper thread
- Same Security and Host Settings
- Data Stored in Logical Call Context available
Demo
There is a performance hit due to copying thread context data from the initial thread to a helper thread. We can suppress / restore the flow of thread context data (generally in the I/O Operations) using the ExecutionContext
class and its method ExecutionContext.SuppressFlow()
.
Let's see below example to control Flow of Execution Context in Threadpool.
//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Runtime.Remoting.Messaging;
using System.Security.Principal;
using System.Diagnostics;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
//Put some data into the Main’s thread logical context
CallContext.LogicalSetData("DummyKey", "DummyValue");
// Create a new instance of the identity class and initialize it with the name you want it to hold
GenericIdentity MyIdentity = new GenericIdentity("MyUser");
// Create a new instance of the GenericPrincipal class and initialize it with the
// previously created GenericIdentity object and an array of strings that represent the roles that you want
// associated with this principal.
String[] MyStringArray = {"Manager", "Teller"};
GenericPrincipal MyPrincipal = new GenericPrincipal(MyIdentity, MyStringArray);
// Use the following code to attach the principal to the current thread.
Thread.CurrentPrincipal = MyPrincipal;
// We get data from the Main’s thread logical context
ThreadPool.QueueUserWorkItem(
state =>
{
Trace.WriteLine("The helper’s thread context allowed to copy the main’s thread context");
Trace.WriteLine(String.Format("Call context data: {0}", CallContext.LogicalGetData("DummyKey")));
Trace.WriteLine(String.Format("Thread.CurrentPrincipal.Identity.Name: {0}", Thread.CurrentPrincipal.Identity.Name));
}
);
//Now, let’s do some optimization and suppress the flow of the Main’s thread execution context
ExecutionContext.SuppressFlow();
//So now, since we have suppressed the flow of the Main’s thread execution context, we can’t get any data
ThreadPool.QueueUserWorkItem(
state =>
{
Trace.WriteLine("Suppressed flow");
Trace.WriteLine(String.Format("Call context data: {0}", CallContext.LogicalGetData("Key")));
Trace.WriteLine(String.Format("Thread.CurrentPrincipal.Identity.Name: {0}", Thread.CurrentPrincipal.Identity.Name));
}
);
//Let’s other threads to get access to the thread logical context
ExecutionContext.RestoreFlow();
Console.ReadKey();
}
}
}
References
Execution context
How to: Create GenericPrincipal and GenericIdentity Objects