开发者

Does WCF break the lock keyword?

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

It gives the following example, which seems to indicate that WCF completely breaks the lock keyword in C#:

public class MyService : IContract
{
    //author of article originally did not initialize this in his illustration
    //initializing it here so that we can avoid talking about side issues.
    public static object wait_handle = new object();

    public int LongOperation()
    {
        lock (wait_handle)
        {
            Before(); //Thread1 has the lock

            LongWait(); //Threads might be switched here

            After(); // Thread2 does not have the lock but
                        it runs.
            return 0;
        }           
    }


    public int SecondOperation()
    {
        // If accidently Thread1 is allocated it has the handle and would enter the lock.
        lock (wait_handle)
        {
            DoWork();
        }

        return 0;
    }
}

This just seems like it would be a horrible decision on Microsoft's part, since it breaks the common usage of a keyword, and means that I can't reliably use any previously developed libraries of code from within WCF services unless I verify that they don't use "lock" in their code. (I presume that if the article is true, this means that the lock keyword uses som开发者_如何转开发e sort of thread-local type storage).

Did Microsoft really do this? Or am I missing something? Or is the referenced article inaccurate?


I think that the author of that article has misunderstood what a lack of thread affinity means within a WCF service. MSDN has an excerpt available from the book Programming WCF Services specifically relating to concurrency that would be worth reading through.

The short answer seems to be that, in a multi-call concurrency model, you cannot be assured that the thread you're using within a service has the required affinity that you're looking for (for example, if your thread requires use of thread-local storage or that it run on the UI thread). You can specifically set this through use of a SynchronizationContext, but once the service is entered the thread affinity for that call is locked down.

Incoming service calls execute on worker threads from the I/O completion thread pool and are unrelated to any service or resource threads. This means that by default the service cannot rely on any kind of thread affinity (that is, always being accessed by the same thread). Much the same way, the service cannot by default rely on executing on any host-side custom threads created by the host or service developers.

There is no reason that a thread under WCF might arbitrarily stop what it was doing, marshal over everything that it was currently doing and had access to and begin a new thread with that same context right in the middle of a call. That would highly dangerous and hardly provide the kind of scalability that the author claims this provides. Monitor.Enter() and the lock statement are perfectly acceptable to use within a WCF service provided that your code requires that level of synchronization.


Make sure you are locking to an instance, not just null.

public static readonly object wait_handle = new object();


It looks like you're missing something very important: WCF may or may not always be executing in the same process. If WCF operates in a single process and you lock on a static object, you will have a valid lock.

If, on the other hand WCF is not operating in a single process (IIS hosting, for example, could cause this) then your lock would be worthless, as one process would have a lock, but the other process would not.

WCF serves a very specific purpose: client-server communications. Well, there's a little more to it than that, but the vast majority of WCF programming is for SOAP or RESTful web services. When programming such services, it's almost always a good idea to avoid locks because a service may be serving more than one request at a time and locks will cause the other request to pause (which may incur a timeout).

If you are using a resource that needs serial access, find an alternative solution to a single service call.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜