zoukankan      html  css  js  c++  java
  • UI thread client callback和UI thread WCF Service一起工作时死锁的形成原因及解决方法

    前言:

    当WCF service和WCF client都是基于UI时,当服务器端callback客户端时,此时若想对于Service端或者Client端的UI进行update,例如某个控件的状态的改变,需要进行严格的同步管理,否则Service|Client UI thread就会陷入deadlock。

    deaklock形成原因:

    假设有以下一个scenario:

    1个windows forms client已经建立了UI的同步上下文信息(UI SynchronizationContext)和回调对象(callback object)之间的姻联。然后该基于UI的客户端调用一个WCF service,连同其callback reference一起传送至service。 假设WCF service的ConcurrencyMode配置为ReEntrant。那么service在收到这个request之后开始callback 客户端。这就形成了一个死锁!因为对客户端的回调请求是执行在客户端的UI thread中的,而此时该UI thread在等待刚刚发出去的service call的结果。

    有人可能想:将callback operation的MEP(Message Exchange Pattern)配置为IsOneWay可以吗? 还是不行。因为service对client 的callback request还是首先需要被marshaled到client UI thread.

    题外话:如果将service operation和callback operation都设置为IsOneWay可以解决deadlock吗? 您自己去想吧:)

    解决方法:

    解决方法是将service端对client的callback请求设置成异步地(asynchronously)marshal到client UI thread即可

    例如:服务器端operation 请求callback的正确代码如下:

     1 public string DoSomething(int value)
     2         {
     3             MyForm form = System.Windows.Forms.Application.OpenForms[0as MyForm;
     4             SendOrPostCallback del = delegate
     5             {
     6                 form.ServiceLable = callback.OnCallBack();
     7             };
     8 
     9             System.Diagnostics.Debug.Assert(form.MySynchronizationContext != null);
    10             form.MySynchronizationContext.Post(del, null);
    //form.MySynchronizationContext.Send(del,null)就会死锁!!
    11 
    12             return "The string is returned from WCF service";
    13         }

     source code:

    1. service contract and callback contract

    Code

    client UI source code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.ServiceModel;
    using System.Threading;

    namespace UICallBack_DeadLock_Client
    {
        
    public partial class CallBackForm : Form,IMyContractCallback
        {
            
    private MyContractClient proxy;
            
    private SynchronizationContext m_ClientCallBackSynchronizationContext;
            
    private string returnValue = String.Empty;

            
    public CallBackForm()
            {
                InitializeComponent();
                m_ClientCallBackSynchronizationContext 
    = SynchronizationContext.Current;
            }

            
    public string OnCallBack()
            {
                SendOrPostCallback setText 
    = delegate
                {
                    m_ClientLabel.Text 
    = returnValue;
                };

                DialogResult result 
    = MessageBox.Show("please select one answer""callback test", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                m_ClientCallBackSynchronizationContext.Post(setText, 
    null);

                
    return result==DialogResult.Yes?"client answer via Callback is YES":"client answer via Callback is NO";
            }

            
    private void CallBackForm_Load(object sender, EventArgs e)
            {

            }

            
    private void button1_Click(object sender, EventArgs e)
            {
                InstanceContext instanceContext 
    = new InstanceContext(this);
                proxy 
    = new MyContractClient(instanceContext);
                proxy.Connect();
                returnValue
    =proxy.DoSomething(2);
                
            }
        }
    }

    运行screenshot

    For all source code regarding to this article, please press here to download

  • 相关阅读:
    PHP实反向代理-收藏
    微信小程序实例-获取当前的地理位置、速度
    Entity Framework Core 实现读写分离
    将ASP.NET Core应用程序部署至生产环境中(CentOS7)(转)
    Centos 7防火墙firewalld开放80端口
    Asp.net Core 使用Redis存储Session
    .net core 使用Autofac依赖注入
    .net core 1.0 实现负载多服务器单点登录
    用ASP.NET Core 1.0中实现邮件发送功能-阿里云邮件推送篇
    阿里大鱼.net core 发送短信
  • 原文地址:https://www.cnblogs.com/Winston/p/1346910.html
Copyright © 2011-2022 走看看