Some time ago, just to open a multi-threaded call to multiple components on a Web application, these components are developed by other teams (such as India/Russia), so modifying their code may seem unrealistic, but It is annoying that their code is heavily used to appcontext.current this object (actually used HttpContext.Current.Item to store), and once asynchronous, HttpContext.Current no longer exist, nature will continue to quote the empty reference Often, it seems that async is not very realistic.
When there was nothing to do, I suddenly found a strange class called CallContext, Hiding in System.Runtime.Remoting.Messaging, the little namespace below, of course, at first I was only attracted by its name, literal translation is not the calling context? Feel that this thing can be a little useful. So I looked at MSDN and described the following:
Provides a set of properties that are passed along with the execution code path. This class cannot be inherited.
A word of nonsense ... Read the notes:
CallContext is a dedicated collection object that resembles a thread-local store of method calls and provides a data slot that is unique to each logical execution thread. Data slots are not shared between call contexts on other logical threads. You can add an object to the CallContext when it is propagated round-trip along the execution code path and is checked by individual objects in that path.
When a remote method call is made to an object in another AppDomain, theCallContext class generates a LogicalCallContext instance that propagates with the remote call. Only objects that are exposed to the ILogicalThreadAffinative interface and stored in CallContext are propagated to the AppDomain in logicalcallcontext External. Objects that do not support this interface are not transferred with the remote method call in the logicalcallcontext instance .
There seems to be some meaning, but the definition of logical threads seems a bit ambiguous, but also mentions an interface ilogicalthreadaffinative, and then look at what this interface defines, a look at the member definition ... No members ... An empty interface, sweat it out, or look at how it's described on MSDN:
Tags can propagate to objects outside the AppDomain in LogicalCallContext.
Emphasize the role in remoting, and then look at the notes:
When a remote method call is made to an object in another AppDomain , the current CallContext class generates a LogicalCallContextthat will propagate to the remote location along with the call. Only objects that are exposed to the ilogicalthreadaffinative interface and stored in CallContext are propagated outside the AppDomain . Objects that do not support this interface are not transferred with the remote method call in the logicalcallcontext instance.
Also emphasizes the role in remoting, but it can be imagined that basically callcontext is used in a way similar to is ilogicalthreadaffinative, to distinguish between different objects, For those conforming to this interface will be placed into the logicalcallcontext, while the non-conforming additional processing.
From the point of view of the document, there seems to be no progress, when, suddenly think of a very interesting type of executioncontext have seen before, namespace is system.threading, which looks like a multithreaded preparation, but the example on MSDN tells you how to control the problem of passing permission objects, and doesn't say how to pass a normal object.
In the moment think of the so-called LogicalCallContext will not exist in the ExecutionContext? Check out MSDN and see the notes:
The ExecutionContext class provides a single container for all information related to the execution of logical threads. This includes the security context, the call context, and the synchronization context.
The ExecutionContext class provides functionality that allows users to capture and transfer this context between user-defined asynchronous points. The common language runtime ensures that ExecutionContext is consistently transferred between asynchronous points that run library definitions within the managed process .
The execution context is the managed equivalent of a COM cell. In an application domain, the entire execution context must be transferred each time a thread is transferred. In the by Thread.::. This occurs during the transfer process caused by the Start method, most thread pool operations, and Windows Forms thread marshaling through the Windows message pump. This behavior does not occur in unsafe thread pool operations, such as the Unsafequeueuserworkitem method, because unsafe thread pool operations do not transfer the compressed stack. The managed principals, synchronizations, locales, and user contexts also flow whenever the compressed stack flows. The ExecutionContext class provides capture and createcopy methods to get the execution context and provides the Run method to set the execution context of the current thread.
The executioncontext associated with a line threads cannot be set on another thread. Attempting to do so causes an exception to be thrown. To propagate executioncontext from one thread to another, make a copy of the ExecutionContext.
ExecutionContext stores all data associated with the LogicalCallContext internally. This makes it possible to propagate logicalcallcontext data while replicating and transmitting ExecutionContext .
Sure enough, there are logicalcallcontext data in the ExecutionContext, and it's good to note that Whether it's Thread.Start or the thread pool, ExecutionContext will automatically pass that data to those threads (the Threadpool.unsafequeueuerworkitem method believes that it shouldn't be a lot of people), and it looks like the actors are all here, right now. You can play a multi-threaded game.
The first is to play a key role in the Exectioncontext, maybe there is no need to appear in our code, but that is only because of the. NET class library method, for us to encapsulate this feature well, without it, want to put an object in one thread to tell another thread, only through the heap.
Secondly, LogicalCallContext, many of the objects that are propagated by ExecutionContext are not easy to use (we cannot define a custom permission to propagate an object), And LogicalCallContext is the best carrier for custom objects.
Finally, the rest of the question is how to read and write this logicalcallcontext problem, that is, finally the turn to CallContext appearance. Take a look at what CallContext has prepared for us: GetData, SetData, Logicalgetdata, Logicalsetdata, FreeNamedDataSlot, GetHeader, SetHeader and Hostcontext properties.
The first focus, of course, is GetData and SetData these two methods, did a simple test, found that the two methods, really is through the ILogicalThreadAffinative interface to decide whether to send the object to the new thread, The way to delete this data is FreeNamedDataSlot, now as long as each of the objects to be used in the multi-threaded object to add an empty interface, and before the start of multithreading in the main thread to set the object in, and then in other threads to remove the problem can be fixed. After the multi-threaded section, do not forget to use FreeNamedDataSlot to delete.
Do not know that everyone noticed, out of the GetData and SetData, there are a pair of logicalgetdata and Logicalsetdata, what is the two? What's the relationship with LogicalCallContext's logical?
Again the simple experiment in the front, but with the Logicalgetdata and logicalsetdata the two methods, the conclusion is whether or not to implement the ILogicalThreadAffinative interface, the object can be accessed within the new thread, This means that any data can now be propagated to new threads, including basic types such as String,int defined by. NET, and this scheme is nearing perfection.
Look back at my task, just modify the implementation of the Appcontext.current property, and do a little processing before and after the multithreading begins, and the rest of the components can run on their own threads in their entirety.
The work is over.
In terms of what the Callcontext.hostcontext property is doing, after a simple test, found in the ASP. NET program, this hostcontext inside is HttpContext instance, Ms also lazy enough. In fact, Ms just makes a very small change, The multi-threading of the ASP is not so troublesome, only need to HttpContext implementation of ILogicalThreadAffinative interface, no matter how many new threads to open, there can be access to httpcontext.current, of course, Ms did not do so is a reason, a Once HttpContext is propagated to other threads, it is difficult for ASP to control the life cycle of the HttpContext object, and the HttpContext object references the HttpRequest object, which may have a much larger side effect than imagined.
CallContext and multithreading