您的位置:首页 > 产品设计 > UI/UE

UI thread client callback和UI thread WCF Service一起工作时死锁的形成原因及解决方法

2008-12-03 17:18 344 查看
前言:

当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[0] as 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

namespace UICallBack_DeadLock_service

{

[ServiceContract]

interface IMyContractCallBack

{

[OperationContract]

string OnCallBack();

}

[ServiceContract(CallbackContract=typeof(IMyContractCallBack))]

interface IMyContract

{

[OperationContract]

string DoSomething(int value);

[OperationContract]

void Connect();

}

class MyContract:IMyContract,IDisposable

{

public IMyContractCallBack callback;

public void Connect()

{

callback = OperationContext.Current.GetCallbackChannel<IMyContractCallBack>();

}

public string DoSomething(int value)

{

MyForm form = System.Windows.Forms.Application.OpenForms[0] as MyForm;

SendOrPostCallback del = delegate

{

form.ServiceLable = callback.OnCallBack();

};

System.Diagnostics.Debug.Assert(form.MySynchronizationContext != null);

form.MySynchronizationContext.Post(del, null);

/*若写成form.MySynchronizationContext.Send(del, null);则对于client 的callback请求会被同步地marshaled 到client UI thread,而client UI thread在等待service call的结果,从而形成deadlock*/

return "The string is returned from WCF service";

}

public void Dispose()

{

}

}

}

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐