WCF回调中的死锁

一、服务器端死锁

对于如下服务:

[ServiceContract(CallbackContract = typeof(INotify))]
    public class DownloadService
    {
        [OperationContract]
        public void Download()
        {
            //开始下载操作
            //.....

            //通知下载完成
            var callback = OperationContext.Current.GetCallbackChannel<INotify>();
            callback.DownloadComplete();
        }
    }

    interface Inotify
    {
        [OperationContract]
        void DownloadComplete();
    }

首先我们用一个控制台程序作为客户端,代码如下:

class Program
    {
        static void Main(string[] args)
        {
            var context = new System.ServiceModel.InstanceContext(new CallBack());
            var client = new DownloadServiceClient(context);
            client.Download();
        }
    }

    class CallBack : DownloadServiceCallback
    {
        public void DownloadComplete()
        {
            Console.WriteLine("finished");
        }
    }

当运行这个程序时,会出现如下异常:

未经处理的异常: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: 此操作将死锁,因为在当前邮件完成处理以前无法收到答复。如果要允许无序的邮件处理,则在 ServiceBehaviorAttribute 上指定可重输入的或多个 ConcurrencyMode。

这个异常已经说得非常清楚了:当前服务不支持并发,在处理Download函数的时候信道是串行的,返回消息的时候必须先返回Download函数的处理消息,再返回DownloadComplete回调获取回调的返回结果;但Download函数本身又在等待DownloadComplete函数返回,从而形成了一个死锁。

这个异常同时也告诉了我们一个修改方案:修改服务的ServiceBehavior的ConcurrencyMode为Reentrant或Multiple即可。

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class DownloadService

实际上,这个问题还有另一种解决方案:如果无需等待回调完成,可以把回调函数设置为OneWay的方式;这样Download函数就不等待回调函数的返回结果了,不会因为互相等待而导致死锁。

interface Inotify
    {
        [OperationContract(IsOneWay=true)]
        void DownloadComplete();
    }

二、客户端死锁

由于系统自己能分析出服务器端的死锁,服务器端的死锁还是比较容易发现和处理的。但客户端的死锁就不是那么容易发现了。

经过前面的处理后,服务器端死锁问题已经解决了,客户端可以顺利处理了。这次我们把客户端代码放到WinForm版本的程序中,放在UI线程中处理。

private void button1_Click(object sender, EventArgs e)
    {
        var context = new System.ServiceModel.InstanceContext(new CallBack());
        var client = new DownloadServiceClient(context);
        client.Download();
    }

当运行上述代码时,可以发现:点击按钮后,窗口就无响应了。由于此时没有任何错误提示信息,我就直接给出错误原因了:WCF的回调函数默认是在UI线程中执行,因此就会出现Download函数等待DownloadComplete回调执行完后才返回,而DownloadComplete回调又因为Download函数又等待着Download函数返回释放UI线程才能执行,这样又形成了一个死锁。而控制台程序没有UI线程,不会出现这种死锁。

对于这种死锁,根本的方案就是修改回调回调函数的通知线程,将其改为在非UI线程中执行。WCF中可以通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
class CallBack : DownloadServiceCallback

我在这里还设置了CallbackBehaviorAttribute的ConcurrencyMode参数,这个参数在本例中是不必要的,但我还是习惯性的将其带上了,至于它在什么时候会用到,请读者朋友们自行分析。

原文地址:点击打开链接

时间: 2024-10-28 04:45:00

WCF回调中的死锁的相关文章

在SQL Server 2005中解决死锁

server|解决 数据库操作的死锁是不可避免的,本文并不打算讨论死锁如何产生,重点在于解决死锁,通过SQL Server 2005, 现在似乎有了一种新的解决办法. 将下面的SQL语句放在两个不同的连接里面,并且在5秒内同时执行,将会发生死锁. use Northwind begin tran     insert into Orders(CustomerId) values('ALFKI')     waitfor delay '00:00:05'     select * from Ord

实例讲解如何在DB2 UDB中监控死锁的发生

前言:这篇文章通过具体的实例阐述了如何在DB2 UDB 中监控死锁的发生.在DB2 UDB中有两种类型的监控器:快照监控器和事件监控器.快照顾名思义就是数据库连续状态下的一个切面,通过快照监控器,你可以很方便地查看当前连接的应用程序,当前等待的锁,当前的死锁,以及正在执行的SQL语句,同时你可以查看缓冲区,表和表空间的用法.假如保存历史数据,并且能够做出比较,对于分析数据库的并发性能有很大的帮助. 但是我们并不能猜测什么时候发生死锁,所以假如有一个后台程序能够一直监控数据库的活动,记录下所有的死

[WCF]配置文件中Certificate 的encodeValue怎么设置?

在WCF配置文件中经常会出现这样的属性:   <identity> <certificate encodedValue="large string!!!!!!!" /> </identity>     那么这其中的encodedValue如何设置?   1.把cer文件(证书)导出为base64格式 a,使用mmc找到需要的证书  -- (Add Snap-In) b,右击证书  导出    c,base64 encoded x509(.cer) 2

SQLServer中的死锁的介绍

原文:SQLServer中的死锁的介绍 简介      什么是死锁?      我认为,死锁是由于两个对象在拥有一份资源的情况下申请另一份资源,而另一份资源恰好又是这两对象正持有的,导致两对象无法完成操作,且所持资源无法释放.       什么又是阻塞?      阻塞是由于资源不足引起的排队等待现象.比如同时两个进程去更新一个表.      这里我们可以把阻塞作为死锁的必要条件.下面我们先理解一下死锁和阻塞再来看一下我最近遇到一个问题以及解决思路. SQLServer中的死锁      对应到

Android异步回调中的UI同步性问题

Android程序编码过程中,回调无处不在.从最常见的Activity生命周期回调开始,到BroadcastReceiver.Service以及Sqlite等.Activity.BroadcastReceiver和Service这些基本组件的回调路径和过程也就是通常意义上所谓的"生命周期".同时,在处理具体的业务逻辑时,常常设计到不同线程之间的通信,如下载图片完成后通知 UI线程更新UI,凡此类场景,无论使用哪一种具体的线程间通信方式(Handler/Message.Handler/p

objc 中block回调中的__block用法

问题描述 objc 中block回调中的__block用法 刚学到objc的代码块回调,在init里回调的时候 老师在前面加了一个用__weak __block 修饰的本类的指针 copy_self= self. 然后才在代码块里用copy_self来判断和调用 比如在room里: __weak __block room * copy_self = self; 请问为什么呢?新手求解0.0 解决方案 Block 回调block回调block回调

WCF项目中出现常见错误的解决方法:基础连接已经关闭: 连接被意外关闭

原文:WCF项目中出现常见错误的解决方法:基础连接已经关闭: 连接被意外关闭 在我们开发WCF项目的时候,常常会碰到一些莫名其妙的错误,有时候如果根据它的错误提示信息,一般很难定位到具体的问题所在,而由于WCF服务的特殊性,调试起来也不是那么方便,因此往往会花费不少时间来进行跟踪处理.本文介绍我在我在我的框架里面使用WCF服务的时候,出现的一个常见错误的处理方法,它的提示信息是:基础连接已经关闭: 连接被意外关闭.这种情况我碰到的有两种,一种是返回DataTable的时候出现的,一种是返回实体类

多线程中的死锁举例与分析(转)

  1. 一个特殊构造的程序考虑下面这个专门为说明多线程中的死锁现象而构造的程序: import java.util.LinkedList; public class Stack { public static void main(String[] args) { final Stack stack = new Stack(); new Thread("push") { @Override public void run() { for (int i = 0; i < 100;

Android异步回调中的UI同步性问题分析_Android

Android程序编码过程中,回调无处不在.从最常见的Activity生命周期回调开始,到BroadcastReceiver.Service以及Sqlite等.Activity.BroadcastReceiver和Service这些基本组件的回调路径和过程也就是通常意义上所谓的"生命周期".同时,在处理具体的业务逻辑时,常常设计到不同线程之间的通信,如下载图片完成后通知 UI线程更新UI,凡此类场景,无论使用哪一种具体的线程间通信方式(Handler/Message.Handler/p