您的位置:首页 > 编程语言 > C#

C# 采集 :设计一个可超时的阻塞方法

2008-10-30 00:34 309 查看
有时候我们调用一个第三方的会阻塞的方法,我们要想法做一个调用超时值,一般来说就是另起一个线程加join的办法,这里有另外一种思路,但也不是完全的解决办法,希望大家多多讨论。
下面是咱们的一个方法,很简单,一个执行方法,一个终止方法,一个和执行方法签名相同的公开委托。

class MyHelper

上面的类的Excute方法是阻塞的,如果传入的a参数是一个特别大的值,调用这个方法的代码会阻塞很长的时间,如果客户端的很多请求都要调用这个方法,而且你的系统实现了多线程,用线程池线程来处理用户的每一个请求,这就有问题了,没过多久,你的线程池就耗尽了。这时候用下面的办法可以加上一个超时逻辑。

private static void InvokeExcute()

以上的示例代码调用的Excute方法要执行5秒,而我们设置了3秒的超时时间,到了3秒咱们就终止调用。以后如果自己要写这种可能会阻塞的方法就加一个Abort的方法来终止操作并清理资源,像HttpWebRequest类就是这么设计的,有一个Abort方法。

但是:如果这个会阻塞的方法不是你写的,是第三方提供的,而且还没有Abort方法,这时候虽然RegisterWaitForSingleObject的超时回调会执行,但是BeginInvoke执行的委托还会在线程池里继续执行,也就是还是有可能把线程池耗尽,我的建议是对于不了解的第三方方法,或者已知会阻塞的方法,不要让线程池去调用它。线程池适合处理那种快速返回的方法。
再有一个人们就说了,我自己实现一套线程池,线程池里执行一个方法超时后,我就调用Thread.Abort来终止这个线程,呵呵,想的倒挺好,.net里如果有个线程调用了非托管的代码,如果你Abort了这个线程,这个线程不会立刻抛出ThreadAbort异常,而会等待非托管代码返回托管代码才会抛出异常,那你还是没解决问题。像这种情况很多,就说常用的Socket.BeginConnect吧,虽说是异步的,可也是有可能阻塞个几十秒的,其实大多时间在DNS解析上。像这种问题,基本上没解,除非你自己去重写Windows的Socket实现去吧,貌似用c++写的Socket.connect函数也不好控制超时参数,也是用消息循环或者多个线程来实现,说是有个注册表键值,貌似也不怎么管用。

总结:很郁闷,没找到答案,也许我把问题想复杂了。
参考链接:http://morganchengmo.spaces.live.com/blog/cns!9950CE918939932E!1586.entry
强烈建议dudu自动把http开头的文字加上超链接,每次我还得自己加。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: