3

我在 WCF 服务上有一个死锁问题,我不明白为什么,因为每个调用都在同一个锁上同步。这是我的客户端/服务配置。

绑定="netTcpBinding"

服务配置:ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,ConcurrencyMode = ConcurrencyMode.Reentrant,UseSynchronizationContext = false)

回调配置: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 informti (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 timeout)
ࡓystem.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs
) Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
ࡓystem.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

[0] 处重新抛出异常:
系统.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
系统.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 类型
) .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(Object parameter) dans c:\dev\GitProjects\NetsCoreLibProject\NetsCoreLib\Nets.Core.Prototype.Client\ViewModels\OrderManagerViewModels\OrderManagerViewModel.cs:ligne 302

下面的服务器日志显示DoAction()回调执行之前的返回。

做动作通话记录:

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|无法验证过滤器订单一致性检查 2015-01-16 11:13:57,342 [27] 信息 - (RemoteOrderManagerService.cs:208) - CancelOrder : RemoteOrderService : CancelOrder 动作返回完成

CallbackAfterDoAction 通话记录:

2015-01-16 11:13:57,342 [EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] 信息 - (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]|Owner=[]]: 无法执行request=[CANCEL] 原因 Order=[[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|Owner=[]] 处于最终状态=[CANCELLED] 2015-01-16 11:13 :57,343 [EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] 信息 - (Order.cs:765) - OnCancelAck : OnCancelAck [[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|Owner=[]] : 从 Nets.Core.Service.Remote.RemoteOrderManagerService 调用

但是:当我评论服务上的回调调用时, DoAction() 方法正确执行。当死锁发生时,它就像在 DoAction 方法返回之前调用回调一样。我不明白会发生什么,因为调用的每个方法都在同一个锁上同步。

PS:如果我在回调调用之前添加睡眠:

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

死锁在 Sleep(3) 之前永远不会发生,但对于值 < 3 ms 时,就会发生死锁。==> 那么问题是为什么回调是在 DoAction() 方法的返回语句之前处理的,而日志却相反?

4

0 回答 0