Condividi tramite


IInstanceContextProvider threading model

IInstanceContextProvider is the extension used by WCF runtime to associate/create InstanceContexts for every Message being processed. As I mentioned earlier this extension is called for every message arriving on every channel. This means that two messages from the same channel can race with each other in trying to get an InstanceContext. This is not an issue for InstanceContextMode.PerCall and InstanceContextMode.Single for obvious reasons. In case of PerCall each message gets its own InstanceContext and in Single case the Singleton is established when the ServiceHose is opened and so every message will get the same InstanceContext. So if you are using the extension to custom wire your InstanceContext creation/association logic then you need to be aware of the potential race. To make matters simple I am going to take an example of user implementing the PerSession behavior. Lets see a sequence when the first n messages from a sessionful channel are processed by the host. I talk about the first n messages only, as once the InstanceContext has been created and associated with the Channel then each message can easily look it up. Lets take a look at sequence for the first 2 messages (different colors for different threads)

Channel1->Message1->IInstanceContextProvider.GetExistingInstanceContext() ==>No InstanceContext exists yet so null is returned.

Channel1->Message2->IInstanceContextProvider.GetExistingInstanceContext() ==>No InstanceContext exists yet as Message1 has not completed InitializeInstanceContext() yet and so null is returned.

Channel1->Message1->IInstanceContextProvider.InitializeInstanceContext() ==>New InstanceContext was created and is associated with the sessionful channel.

Channel1->Message2->IInstanceContextProvider.InitializeInstanceContext() ==>One more InstanceContext was created and now that will be associated with the channel.

So when Message2 from Channel1 starts processing and IInstanceContextProvider is invoked, its on a different thread and this now races with Message1.InitializeInstanceContext() running on a different thread. If null is returned from GetExistingInstanceContext() for both messages and so two new InstanceContext's are created. So based on how many messages arrive before the InstanceContext is hooked to the sessionful channel, the system can potentially create that many InstanceContexts for the same channel. If Message1 runs through both the methods before any other message is processed for the same channel then there is no issue.

The solution is to make the second message block in GetExistingInstanceContext() till the first message completes initializing the InstanceContext. For more details on how to achieve this, refer to the SDK sample shipping with WCF under (TechnologySamples\Extension\Instancing\Sharing).

So another question is whether this is an issue only for ConcurrencyMode.Multiple and the answer is no. It's an issue for all ConcurrencyMode's as that check is enforced at a later stage by the runtime.

Maheshwar Jayaraman[WCF]