如果在与当前上下文相同的线程中调用,则WCF回调锁定

时间:2013-05-01 13:05:06

标签: c# .net wcf callback deadlock

我希望我能说得对。我有一个我正在使用的WCF服务(双工通道通信),其中一个客户端向服务注册。服务的注册方法返回一个值。我希望被调用服务注册方法的方法也调用回调方法,该方法将发送客户端注册的通知(我有我的理由并在此解释它只会混淆问题)。问题是客户端实现的回调必须在主应用程序线程中运行才能正常工作(主要是因为与第三方应用程序的集成)。服务注册方法调用也在同一个线程中发生,因此它有效地锁定,因为客户端正在寻找从保持回调方法能够运行的线程的服务注册方法的返回。如果我告诉它为除刚注册的所有上下文之外的所有上下文调用所有回调方法,它就可以正常工作。但是,如果我告诉它包含它,显然它会锁定,因为该线程已被锁定。我可以将UseSynchronizationContext的回调属性属性设置为false,但这意味着在与main的单独线程上调用回调方法,现在程序的其余部分将无法工作。任何帮助将不胜感激。

这基本上是注册方法(初稿......)

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
                    UseSynchronizationContext = false,
                    ConcurrencyMode = ConcurrencyMode.Multiple,
                    Namespace = "http://MyApp/Design/CADServiceTypeLibrary/2012/12")]
    public class DTOTransactionService : IDTOTransactionService, IDisposable
    {
             //some more stuff

public CADManager RegisterCADManager(int processID, bool subscribeToMessages)
        {

            List<CADManager> cadMgrs = this.CADManagers;

            bool registered = false;

            //Create new CADManager mapped to process id
            CADManager regCADManager = new CADManager(processID);

            //Add to CADManagers List and subscribe to messages
            if (regCADManager.IsInitialized)
            {
                cadMgrs.Add(regCADManager);
                this.CADManagers = cadMgrs;

                //Subscribe to callbacks
                if (subscribeToMessages)
                    SubscribeCallBack(regCADManager.ID);

                registered = true;
            }

            //Send registration change notification
            RegistrationState state;
            if (registered)
                state = RegistrationState.Registered;
            else
                state = RegistrationState.RegistrationException;

            foreach (CallBackSubscriber subscriber in this.CallBackSubscribers)
            {
                    subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state);
            }

            return regCADManager;
        }
}

1 个答案:

答案 0 :(得分:1)

我想我已经明白了。令我印象深刻的是,正在发生的事情是因为对service方法的调用期望返回值,并且因为回调将发生在与客户端方法相同的线程中,期望返回值,这可能是死锁的结果条件。然后我决定尝试使用不同的线程调用服务中的回调方法来解决当前的线程条件。换句话说,解决当前线程的方法尚未从服务方法提供返回值。有效!这是正确的方法吗?我有足够的经验在这里很危险,所以如果其他人的经验表明这是处理这个问题的错误方法,我全都听见了。

        Thread notifyThread = new Thread(delegate()
        {
            foreach (CallBackSubscriber subscriber in this.CallBackSubscribers)
            {
                subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state);
            }
        });

更新:

是的,线程和死锁条件是问题,但是我最近发现的更合适的修复是使用SynchronizationContext。要使用,请创建SynchronizationContext类型的属性或字段,然后在要使用SynchronizationContext.Current捕获的上下文中将值分配给字段/属性。然后,在Service调用的回调方法中使用Post()方法(通过SendOrPostCallback对象提供委托)。一个简短的例子:

  private SynchronizationContext _appSyncContext = null;

  private DTOCommunicationsService()
    {
        this.AppSyncContext = SynchronizationContext.Current;

        //Sets up the service proxy, etc, etc
        Open();
    }

  // Callback method
    public void ClientSubscriptionNotification(string clientID, SubscriptionState subscriptionState)
    {
        SendOrPostCallback callback = delegate(object state)
        {
            object[] inputArgs = (object[])state;
            string argClientID = (string)inputArgs[0];
            SubscriptionState argSubState = (SubscriptionState)inputArgs[1];

            //Do stuff with arguments

        };

        _appSyncContext.Post(callback, new object[] { clientID, subscriptionState });
    }