One of the libraries our WCF service references uses a ThreadStatic variable. The service method sets its value at the beginning of each call. I'm wondering if this is safe - in other words, can we guarantee that exactly one thread will be used exclusively for the entire call? Or is it possible that a call could begin on one worker thread and finish on another? Or could a worker thread be swapped to a different method call and then back again?

We are using the defaults of ConcurrencyMode.Single and InstanceContextMode.PerSession.

EDIT

The only information I have been able to find so far is this blog post, which states that it is possible for a call to be processed by multiple threads:

http://blogs.microsoft.co.il/blogs/applisec/archive/2009/11/23/wcf-thread-affinity-and-synchronization.aspx

Is this guy correct? Is there any definitive information from Microsoft?

有帮助吗?

解决方案

If you are not sure you can always use the CallContext class: CallContext.LogicalSetData CallContext.LogicalGetData

While ThreadStatic won't work if the thread did change, the Logical CallContext is passed around in .NET, even if you would create your own new thread/task.

其他提示

The phenomenon you're talking about whereby a single request can be passed between multiple requests is referred to as "thread agility".

The short answer is that no, you cannot guarantee that a given request will be processed by a single thread.

See the accepted answer here: Are WCF request handling Thread Agile?

*This is the case for WCF hosted out of IIS

Here is a response from one of my collegues:


“This guy” that you referenced has to be wrong. There is no way for a thread to be changed within the middle of execution of the actual service method. This is true of any method and isn’t related to WCF.

It is possible to create an async call which is then completed on another method/thread; but that isn’t anything special: http://tao.qshine.com/note/ThreadIssue.html

I’d of course be very interested to hear if this thread agility thing actually relates to method calls switching threads … we are talking about managed threads here, there would be no reason for Microsoft to change the thread id. The CallContext is a feature that Microsoft provides so that you can store state if YOU perform async calls.

It might be possible that the instance context uses a different thread to instantiate the service than execute the method – though if you use PerCall this will not happen. Are you really using sessions; if not you should switch to PerCall. It is possible that different calls within the same session will use a different thread.


Seems to make sense. Any comments?

I have the save problem. To investigate that I start load tests and start to test GetRolesForUser:

public override bool IsUserInRole(string username, string roleName)
    {
        object stub = new object();
        bool res;
        lock(stub)
        {
            RoleProviderCount++;
            ThreadId = Thread.CurrentThread.ManagedThreadId;
            res = GetRolesForUser(username).Contains(roleName);
        }
        return res;
    }

this is my log:

Timestamp: 06.11.2012 13:55:03 Message:  ServiceCalls count 1; RoleProvider count 1 Thread Id 9 
Timestamp: 06.11.2012 14:00:22 Message:  ServiceCalls count 1; RoleProvider count 1 Thread Id 9 
Timestamp: 07.11.2012 5:30:38 Message:  ServiceCalls count 1; RoleProvider count 1 Thread Id 11 
Timestamp: 07.11.2012 5:31:58 Message:  ServiceCalls count 1; RoleProvider count 4 Thread Id 27 
Timestamp: 07.11.2012 5:31:58 Message:  ServiceCalls count 1; RoleProvider count 4 Thread Id 27 
Timestamp: 07.11.2012 5:31:58 Message:  ServiceCalls count 1; RoleProvider count 4 Thread Id 27 
Timestamp: 07.11.2012 5:31:58 Message:  ServiceCalls count 1; RoleProvider count 4 Thread Id 27 
Timestamp: 07.11.2012 5:31:58 Message:  ServiceCalls count 1; RoleProvider count 4 Thread Id 27 
Timestamp: 07.11.2012 5:31:58 Message:  ServiceCalls count 1; RoleProvider count 4 Thread Id 27 
Timestamp: 07.11.2012 5:31:59 Message:  ServiceCalls count 1; RoleProvider count 5 Thread Id 22 
Timestamp: 07.11.2012 5:31:59 Message:  ServiceCalls count 1; RoleProvider count 8 Thread Id 26 
Timestamp: 07.11.2012 5:31:59 Message:  ServiceCalls count 1; RoleProvider count 8 Thread Id 26 
Timestamp: 07.11.2012 5:32:00 Message:  ServiceCalls count 1; RoleProvider count 10 Thread Id 23 
Timestamp: 07.11.2012 5:32:00 Message:  ServiceCalls count 1; RoleProvider count 11 Thread Id 29 
Timestamp: 07.11.2012 5:32:00 Message:  ServiceCalls count 1; RoleProvider count 12 Thread Id 22 
Timestamp: 07.11.2012 5:32:00 Message:  ServiceCalls count 1; RoleProvider count 13 Thread Id 27 
Timestamp: 07.11.2012 5:32:00 Message:  ServiceCalls count 1; RoleProvider count 14 Thread Id 24 
Timestamp: 07.11.2012 5:32:00 Message:  ServiceCalls count 1; RoleProvider count 15 Thread Id 30 
Timestamp: 07.11.2012 5:32:00 Message:  ServiceCalls count 1; RoleProvider count 16 Thread Id 26 
Timestamp: 07.11.2012 5:32:01 Message:  ServiceCalls count 1; RoleProvider count 17 Thread Id 11
Timestamp: 07.11.2012 5:32:01 Message:  ServiceCalls count 1; RoleProvider count 18 Thread Id 23
Timestamp: 07.11.2012 5:32:01 Message:  ServiceCalls count 1; RoleProvider count 20 Thread Id 26
Timestamp: 07.11.2012 5:32:01 Message:  ServiceCalls count 1; RoleProvider count 20 Thread Id 26
Timestamp: 07.11.2012 5:32:01 Message:  ServiceCalls count 1; RoleProvider count 21 Thread Id 24

So, RoleProvider method was called from same thread. (WCF service configuration instance mode PerCall, concurrency Multiple)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top