簡體   English   中英

如果在與當前上下文相同的線程中調用,則WCF回調將鎖定

[英]WCF Callback locking up if called in same thread as current context

我希望我能正確地說出這句話。 我有一個正在使用的WCF服務(雙通道通信),其中一個客戶端向該服務注冊。 服務的注冊方法返回一個值。 我希望被調用的服務注冊方法的方法也調用回調方法,該方法將發出客戶端注冊的通知(我有這樣做的理由,在這里解釋它只會使問題感到困惑)。 問題在於,客戶端實現的回調必須在主應用程序線程中運行才能正常工作(主要是由於與第三方應用程序集成)。 服務注冊方法調用也發生在同一線程中,因此它有效鎖定,因為客戶端正在尋找從保持該線程的服務注冊方法返回的值,從而使回調方法無法運行。 如果我告訴它為除剛剛注冊的上下文之外的所有上下文調用所有回調方法,那么它可以正常工作。 但是,如果我告訴它包括它,則顯然它已鎖定,因為該線程已被鎖定。 我可以將UseSynchronizationContext的callback屬性設置為false,但這意味着在與主線程不同的線程上調用回調方法,現在程序的其余部分將無法工作。 任何幫助將不勝感激。

基本上就是這種注冊方法(初稿)

[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;
        }
}

我想我已經知道了。 令我驚訝的是,由於對service方法的調用期望返回值,並且由於回調將在與client方法期望返回值的線程相同的線程中發生,因此回調可能是死鎖的結果條件。 然后,我決定嘗試使用其他線程在服務中調用回調方法,以解決當前線程狀況。 換句話說,解決當前線程尚未從服務方法提供返回值的方法。 有效! 這是正確的方法嗎? 我在這里有足夠的危險經驗,因此,如果其他人的經驗表明這是處理此問題的錯誤方法,我將不知所措。

        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 });
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM