/ .NET

6. What Wikipedia Can't Tell You About Thread Execution Contexts (Multithreading Fundamentals)

The series so far:

  1. The Unconventional Guide to Introduction to Thread
  2. Why Do People Think Dedicated CLR Threads is a Good Idea?
  3. How Not Knowing Thread Members and Execution State Makes You a Rookie
  4. Doing Thread Scheduling and Priority the Right Way
  5. How to Start Using CLR's Thread Pool
  6. What Wikipedia Can't Tell You About Thread Execution Contexts
  7. 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
Execution Context

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:

  1. Execution Context flows to the helper thread
  2. Same Security and Host Settings
  3. 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

6. What Wikipedia Can't Tell You About Thread Execution Contexts (Multithreading Fundamentals)
Share this

Subscribe to Coding Today

Popular queries