zoukankan      html  css  js  c++  java
  • 蛙蛙推荐:设计一个可超时的阻塞方法

    有时候我们调用一个第三方的会阻塞的方法,我们要想法做一个调用超时值,一般来说就是另起一个线程加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开头的文字加上超链接,每次我还得自己加。

  • 相关阅读:
    mysql 远程登陆不上
    hdu 5339 Untitled【搜索】
    SqlServer 书目
    passwordauthentication yes
    oracle 11g RAC ocfs2
    Oracle 11g RAC database on ASM, ACFS or OCFS2
    CentOS ips bonding
    Oracle 11g RAC features
    openStack 王者归来之 trivial matters
    openstack windows 2008 img
  • 原文地址:https://www.cnblogs.com/onlytiancai/p/1166512.html
Copyright © 2011-2022 走看看