zoukankan      html  css  js  c++  java
  • C# 采集 :设计一个可超时的阻塞方法

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

    class MyHelper
    {
        
    public delegate int ExecuteDelegate(int a);
        
    volatile bool _stopFlag = false;
        
    public int Execute(int a)
        
    {
            Console.WriteLine(
    "Execute方法执行线程:{0}",Thread.CurrentThread.GetHashCode());
            
    int i = 0;
            
    while (!_stopFlag)
            
    {
                Thread.Sleep(
    1000);
                
    if(++>= a)
                    
    return i;
            }

            
    return i;
        }

        
    public void AbortExecute()
        
    {
            _stopFlag 
    = true;
            Console.WriteLine(
    "终止操作");
        }

    }



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

    private static void InvokeExcute()
    {
        MyHelper h 
    = new MyHelper();
        MyHelper.ExecuteDelegate d 
    = h.Execute;
        IAsyncResult result 
    = (IAsyncResult)d.BeginInvoke(5,
            
    delegate(IAsyncResult ar)
            
    {
                
    int temp = d.EndInvoke(ar);
                Console.WriteLine(
    "回调方法执行线程:{0}", Thread.CurrentThread.GetHashCode());
                Console.WriteLine(
    "执行结果是:{0}", temp);
            }
    , h);
        ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle,
            
    delegate(object state, bool timedOut)
            
    {
                
    if (timedOut)
                
    {
                    
    try
                    
    {
                        ((MyHelper)state).AbortExecute();
                    }

                    
    catch (Exception ex)
                    
    {
                        Trace.TraceError(
    "终止操作出错:{0}",ex);
                    }

                    Console.WriteLine(
    "超时处理线程:{0},已超时",Thread.CurrentThread.GetHashCode());
                }

                
    else
                
    {
                    Console.WriteLine(
    "超时处理线程:{0},未超时", Thread.CurrentThread.GetHashCode());
                }

            }
    ,h, 3000true);
    }

    以上的示例代码调用的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开头的文字加上超链接,每次我还得自己加。

  • 相关阅读:
    EasyUi datagrid列表增加复选框
    List集合流处理类型小结
    MockMvc模拟对controller进行单元测试
    项目配置不带项目名称访问
    mongodb常用的sql语句总结
    git push时报错:Updates were rejected because the tip of your current branch is behind
    xml转json和实体类的两种方式
    win 10 关闭或打开 测试模式
    Wise Force Deleter 强制删除文件工具 ---- 亲测好用
    Win 10 你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问....
  • 原文地址:https://www.cnblogs.com/Fooo/p/1322606.html
Copyright © 2011-2022 走看看