3

WCF サービスでデッドロックの問題が発生しましたが、すべての呼び出しが同じロックで同期されるため、その理由がわかりません。これが私のクライアント/サービス構成です。

binding="netTcpBinding"

サービス構成: ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession、ConcurrencyMode = ConcurrencyMode.Reentrant、UseSynchronizationContext = false)

Callback Config : CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant、UseSynchronizationContext = false)

コード(説明のためにクラス名とメソッド名を簡略化しました):

interface ICallBack{
    void OnDoAction(string info);
}

interface IMyService{
        Report DoAction( string param);
}


public class MyClient:ICallBack{
    void OnDoAction(string info){
        Task.Factory.StartNew(() => {Console.WriteLine("Received info=["+info+"]"); });
    }

    Main(){
        MyClient client = new MyClient();
        InstanceContext context = new InstanceContext(client);
        DuplexChannelFactory<IMyService> duplexChannelFactory = new DuplexChannelFactory<IMyService>(context, "MyService");
        IMyService service =  duplexChannelFactory.CreateChannel();
        Report report = service.DoAction("Param1");
    }
}

public class MyService:IMyService{

    ICallback callback;

   public MyService(){
     callback = OperationContext.Current.GetCallbackChannel<ICallBack>();
   }

    public Report DoAction(){
        lock(callback){
            try{
                Report r = null;
                try{    
                    Log("Do action");
                    r = executeAction();
                }catch(Exception e){
                    r = new Report("Error in DoAction");
                }
                Log("Do action done");
                return report;
            }finally{
                Log("Do action has returned");
            }
        }
    }

    public void CallbackAfterDoAction(string info){
        lock(callback){
            callback.OnDoAction(info);
        }
    }
}

コールバックは、別のスレッドで非同期に呼び出されます。クライアントからメソッドを呼び出すDoAction()と、デッドロックが発生し、TimeoutException が発生します。

2015-01-16 10:42:17,463 [8] エラー - (OrderManagerViewModel.cs:311) - CancelOrder : System.TimeoutException: Cette op곡tion de demande envoyꥠ࡮et.tcp://localhost:8002/NetsOrderManagerServiceRemote/ n'a pas re赠de r걯nse dans le dꭡi informi (00:00:05). Le temps allou顠 cette op곡tion fait peut-뵲e partie d'un dꭡi d'attente plus long. Ceci peut 뵲e d fait que le service est toujours en cours de traitement de l'op곡tion ou qu'il n'a pas pu envoyer un message de r걯nse. Envisagez d'augmenter le dꭡi d'attente de l'op곡tion (en diffusant le canal/proxy vers IContextChannel et en dꧩnissant la propri굩 OperationTimeout) et v곩fiez que le service peut se connecter au client.

サーバースタックトレース:
ystem.ServiceModel.Dispatcher.DuplexChannelBinder.SyncDuplexRequest.WaitForReply(TimeSpan timeout)
ystem.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout)
ystem.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway 、ProxyOperationRuntime 操作、Object[] ins、Object[] outs、TimeSpan タイムアウト)
ࡓystem.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
ࡓystem.ServiceModel. Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime 操作)
ࡓystem.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage メッセージ)

[0] で例外が再スローされました:
ࡓystem.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
ࡓystem.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
ࡎets.Core.API.OrderManager .Service.IOrderManager.CancelOrder(ICancelOrderRequest cancelRequest)
ࡎets.Core.Client.Wcf.OrderServiceWcfClient.RemoteOrderManagerServiceProxy.CancelOrder(ICancelOrderRequest cancelRequest) dans c:\dev\GitProjects\NetsCoreLibProject\NetsCoreLib\Nets.Core.Client.Wcf.OrderServiceWcfClient\RemoteOrderManagerServiceProxy .cs:リーニュ 340
ࡎets.Core.Prototype.Client.ViewModels.OrderManagerViewModels.OrderManagerViewModel.CancelOrder(オブジェクトパラメータ) dans c:\dev\GitProjects\NetsCoreLibProject\NetsCoreLib\Nets.Core.Prototype.Client\ViewModels\OrderManagerViewModels\OrderManagerViewModel.cs:ligne 302

以下のサーバー ログは、DoAction()Callback 実行前に返されることを示しています。

アクション コール ログを行う:

2015-01-16 11:13:57,342 [27] INFO - (RemoteOrderManagerService.cs:195) - CancelOrder : RemoteOrderService : サーバーによって呼び出される CancelOrder アクション 2015-01-16 11:13:57,342 [27] INFO - (RemoteOrderManagerService. cs:203) - CancelOrder : RemoteOrderService : CancelOrder action return report=[CancelOrder report netsd2dce|Failed to validate filter Order Consistency Check 2015-01-16 11:13:57,342 [27] INFO - (RemoteOrderManagerService.cs:208) - CancelOrder : RemoteOrderService : CancelOrder アクション return done

CallbackAfterDoAction コール ログ:

2015-01-16 11:13:57,342 [EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] INFO - (OrderManagerService.cs:451) - DispatchErrorOnOrder: 注文 NetsOrderId[netsd2dce] 2015-01-16 11:13:57,342 でエラーをディスパッチします [ EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] INFO - (Order.cs:760) - OnCancelAck : OnCancelAck[[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|所有者=[]]: 実行できませんrequest=[CANCEL] cause Order=[[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|Owner=[]] is in final state=[CANCELLED] 2015-01-16 11:13 :57,343 [EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] INFO - (Order.cs:765) - OnCancelAck : OnCancelAck[[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|所有者=[]] : Nets.Core.Service.Remote.RemoteOrderManagerService からの呼び出し

BUT: サービスのコールバック呼び出しにコメントすると、DoAction() メソッドが正しく実行されます。デッドロックが発生した場合、DoAction メソッドが戻る前にコールバックが呼び出されたかのように動作します。呼び出されたすべてのメソッドが同じロックで同期されるため、何が起こるかわかりません。

PS:コールバック呼び出しの前にスリープを追加すると:

    public void CallbackAfterDoAction(){
        lock(callback){
            Thread.Sleep(3);
            callback.OnDoAction();
        }
    }

Sleep(3) までデッドロックは発生しませんが、値が 3 ミリ秒未満の場合はデッドロックが発生します。==> 問題は、ログが反対のことを言っているのに、 DoAction() メソッドの return ステートメントの前にコールバックが処理されるのはなぜですか?

4

0 に答える 0