1

これを正しく表現できることを願っています。1 つのクライアントがサービスに登録する WCF サービス (二重チャネル通信) を使用しています。サービスの登録メソッドは値を返します。呼び出されたサービス登録メソッドのメソッドで、クライアント登録の通知を送信するコールバック メソッドも呼び出す必要があります (これには理由があり、ここで説明すると問題が混乱するだけです)。問題は、クライアントに実装されたコールバックが正しく機能するためにメイン アプリケーション スレッドで実行する必要があることです (主にサードパーティ アプリケーションとの統合が原因です)。サービス登録メソッドの呼び出しも同じスレッドで発生しており、そのため、クライアントはコールバック メソッドの実行を妨げているスレッドを保持しているサービス登録メソッドからの戻りを探しているため、事実上ロックアップします。登録したコンテキスト以外のすべてのコンテキストに対してすべてのコールバック メソッドを呼び出すように指示すると、問題なく動作します。しかし、それを含めるように指示すると、そのスレッドはすでにロックされているため、明らかにロックされます。UseSynchronizationContext のコールバック属性プロパティを false に設定できますが、これはコールバック メソッドがメインとは別のスレッドで呼び出されることを意味し、プログラムの残りの部分が機能しなくなります。どんな助けでも大歓迎です。そのスレッドはすでにロックされているため、明らかにロックされます。UseSynchronizationContext のコールバック属性プロパティを false に設定できますが、これはコールバック メソッドがメインとは別のスレッドで呼び出されることを意味し、プログラムの残りの部分が機能しなくなります。どんな助けでも大歓迎です。そのスレッドはすでにロックされているため、明らかにロックされます。UseSynchronizationContext のコールバック属性プロパティを 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;
        }
}
4

1 に答える 1

1

私はそれを理解したと思います。何が起こっているのか、もう少し深く考えてみると、サービス メソッドへの呼び出しは戻り値を期待しており、クライアント メソッドが戻り値を期待しているのと同じスレッドでコールバックが発生するため、これはデッドロックの結果である可能性があるということです。調子。次に、別のスレッドを使用してサービスのコールバック メソッドを呼び出して、現在のスレッドの状態を回避することにしました。つまり、メソッドがまだサービス メソッドからの戻り値を提供していない現在のスレッドを回避します。出来た!これは正しいアプローチでしたか?私はここで危険を冒すのに十分な経験を持っているので、他の誰かの経験がこれを処理する方法が間違っていることを示している場合、私は完全に耳を傾けます.

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

アップデート:

はい、スレッド化とデッドロック状態が問題でしたが、最近発見したより適切な修正は、SynchronizationContext を使用することです。使用するには、タイプ SynchronizationContext のプロパティまたはフィールドを作成し、SynchronizationContext.Current を使用してキャプチャするコンテキスト内で、フィールド/プロパティに値を割り当てます。次に、サービスによって呼び出されるコールバック メソッドで 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 });
    }
于 2013-05-01T23:39:53.537 に答える