3

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?

Mike Chamberlain
  • 39,692
  • 27
  • 110
  • 158
  • Here is a good explanation of [how ThreadStatic attribute works][1] [1]: http://stackoverflow.com/questions/5227676/how-does-the-threadstatic-attribute-work – Bishoy Nov 12 '12 at 22:45

4 Answers4

3

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.

XIU
  • 804
  • 7
  • 11
  • That's pretty awesome - never knew about that one. – Mike Chamberlain Nov 16 '12 at 04:15
  • I didn't realise that refactoring was an option. If you have the option of rewriting the code that's using ThreadStatic, why not just do it properly and use OperationContext? If you need to do stuff with message inspectors then [CallContext is not suitable either](http://stackoverflow.com/questions/3116289/callcontext-in-wcf) – Dan Turner Nov 19 '12 at 06:15
2

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

Community
  • 1
  • 1
Dan Turner
  • 2,233
  • 18
  • 19
  • I expect you are right, but for the bounty I'm looking for official WCF documentation that categorically states such. Do you know of any? – Mike Chamberlain Nov 13 '12 at 03:46
0

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)

Community
  • 1
  • 1
Max Kilovatiy
  • 798
  • 1
  • 11
  • 32
  • Maybe the answer is inside implementation of Concurrency Multiple? And maybe this article can help you http://www.codeproject.com/Articles/89858/WCF-Concurrency-Single-Multiple-and-Reentrant-and#Reentrant – Max Kilovatiy Nov 07 '12 at 06:24
  • Your answer confuses me. Could you add more explanation and/or more code to show how your log file answers the question? – Mike Chamberlain Nov 13 '12 at 04:57
0

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?

Community
  • 1
  • 1
Mike Chamberlain
  • 39,692
  • 27
  • 110
  • 158