It is quite interesting to see how many people don’t understand the basics of threading, while it is a difficult topic (especially to debug), and it is not the silver bullet for all the problems, but it sure is quite handy for certain things. With the inevitable shift to multi-core CPU’s and the release of Vista to take better opportunity of these extra power, more applications in the future should be ready to exploit them. Which makes it quite important for the average developer to start playing and understanding this.

If you are new to this, one of the classes I would recommend reading up on is called ExecutionContext class. This class essentially is the equivalent of the COM Apartment (from the good old COM days). This class provides a single container for all information relevant to a logical thread of execution which includes security context, call context, synchronization context, localization context, and transaction context. You cannot change context of the thread (to which a ExecutionContext is attached), you can only copy it to another thread. If you do try and copy it you will get an Exception.

Here is an example from MSDN on how to use this (also testing the new CopyAsHTML Addin):

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System;
using System.Threading;
using System.Security;
using System.Collections;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Remoting.Messaging;

namespace Contoso
 {
     class ExecutionContextSample
     {
         static void Main()
         {
             try
             {
                 Console.WriteLine("Executing Main in the primary thread.");
                 FileDialogPermission fdp = new FileDialogPermission(
                     FileDialogPermissionAccess.OpenSave);
                 fdp.Deny();
                 // Capture the execution context containing the Deny.
                 ExecutionContext eC = ExecutionContext.Capture();
 
                 // Suppress the flow of the execution context.
                 AsyncFlowControl aFC = ExecutionContext.SuppressFlow();
                 Thread t1 = new Thread(new ThreadStart(DemandPermission));
                 t1.Start();
                 t1.Join();
                 Console.WriteLine("Is the flow suppressed? " +
                     ExecutionContext.IsFlowSuppressed());
                 Console.WriteLine("Restore the flow.");
                 aFC.Undo();
                 Console.WriteLine("Is the flow suppressed? " +
                     ExecutionContext.IsFlowSuppressed());
                 Thread t2 = new Thread(new ThreadStart(DemandPermission));
                 t2.Start();
                 t2.Join();
                 // Remove the Deny.
                 CodeAccessPermission.RevertDeny();
                 // Capture the context that does not contain the Deny.
                 ExecutionContext eC2 = ExecutionContext.Capture();
                 // Show that the Deny is no longer present.
                 Thread t3 = new Thread(new ThreadStart(DemandPermission));
                 t3.Start();
                 t3.Join();
 
                 // Set the context that contains the Deny.
                 // Show the deny is again active.
                 Thread t4 = new Thread(new ThreadStart(DemandPermission));
                 t4.Start();
                 t4.Join();
                 // Demonstrate the execution context methods.
                 ExecutionContextMethods();
                 Console.WriteLine("Demo is complete, press Enter to exit.");
                 Console.Read();
             }
             catch (Exception e)
             {
                 Console.WriteLine(e.Message);
             }
         }

         // Execute the Demand.
         static void DemandPermission()
         {
             try
             {
                 Console.WriteLine("In the thread executing a Demand for " +
                     "FileDialogPermission.");
                 new FileDialogPermission(
                     FileDialogPermissionAccess.OpenSave).Demand();
                 Console.WriteLine("Successfully demanded " +
                     "FileDialogPermission.");
             }
             catch (Exception e)
             {
                 Console.WriteLine(e.Message);
             }
         }
 
         static void ExecutionContextMethods()
         {
             // Generate a call context for this thread.
             ContextBoundType cBT = new ContextBoundType();
             cBT.GetServerTime();
             ExecutionContext eC1 = ExecutionContext.Capture();
             ExecutionContext eC2 = eC1.CreateCopy();
             Console.WriteLine("The hash code for the first execution " +
                 "context is: " + eC1.GetHashCode());
 
             // Create a SerializationInfo object to be used for getting the
             // object data.
             SerializationInfo sI = new SerializationInfo(
                 typeof(ExecutionContext),
                 new FormatterConverter());
 
             eC1.GetObjectData(
                 sI,
                 new StreamingContext(StreamingContextStates.All));
 
             LogicalCallContext lCC = (LogicalCallContext)sI.GetValue(
                 "LogicalCallContext",
                 typeof(LogicalCallContext));
 
             // The logical call context object should contain the previously
             // created call context.
             Console.WriteLine("Is the logical call context information " +
                 "available? " + lCC.HasInfo);
         }
     }
 
 
     // One means of communicating between client and server is to use the
     // CallContext class. Calling CallContext effectivel puts the data in a thread
     // local store. This means that the information is available to that thread
     // or that logical thread (across application domains) only.
     [Serializable]
     public class CallContextString : ILogicalThreadAffinative
     {
         String _str = "";
 
         public CallContextString(String str)
         {
             _str = str;
             Console.WriteLine("A CallContextString has been created.");
         }
 
         public override String ToString()
         {
             return _str;
         }
     }
 
     public class ContextBoundType : ContextBoundObject
     {
         private DateTime starttime;
 
         public ContextBoundType()
         {
             Console.WriteLine("An instance of ContextBoundType has been " +
                "created.");
             starttime = DateTime.Now;
         }

         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
         public DateTime GetServerTime()
         {
             Console.WriteLine("The time requested by a client.");
             // This call overwrites the client's
             // CallContextString.
             CallContext.SetData(
                 "ServerThreadData",
                 new CallContextString("This is the server side replacement " +
                 "string."));
             return DateTime.Now;
         }
     } 
 }