C# 採集 :設計一個可逾時的阻塞方法

來源:互聯網
上載者:User

有時候我們調用一個第三方的會阻塞的方法,我們要想法做一個調用逾時值,一般來說就是另起一個線程加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(++i >= 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, 3000, true);
}

以上的範例程式碼調用的Excute方法要執行5秒,而我們設定了3秒的逾時時間,到了3秒咱們就終止調用。以後如果自己要寫這種可能會阻塞的方法就加一個Abort的方法來終止操作並清理資源,像HttpWebRequest類就是這麼設計的,有一個Abort方法。

但是:如果這個會阻塞的方法不是你寫的,是第三方提供的,而且還沒有Abort方法,這時候雖然RegisterWaitForSingleObject的逾時回調會執行,但是BeginInvoke執行的委託還會線上程池裡繼續執行,也就是還是有可能把線程池耗盡,我的建議是對於不瞭解的第三方方法,或者已知會阻塞的方法,不要讓線程池去調用它。線程池適合處理那種快速返回的方法。
再有一個人們就說了,我自己實現一套線程池,線程池裡執行一個方法逾時後,我就調用Thread.Abort來終止這個線程,呵呵,想的倒挺好,.net裡如果有個線程調用了非託管的代碼,如果你Abort了這個線程,這個線程不會立刻拋出ThreadAbort異常,而會等待Unmanaged 程式碼返回Managed 程式碼才會拋出異常,那你還是沒解決問題。像這種情況很多,就說常用的Socket.BeginConnect吧,雖說是非同步,可也是有可能阻塞個幾十秒的,其實大多時間在DNS解析上。像這種問題,基本上沒解,除非你自己去重寫Windows的Socket實現去吧,貌似用c++寫的Socket.connect函數也不好控制逾時參數,也是用訊息迴圈或者多個線程來實現,說是有個註冊表索引值,貌似也不怎麼管用。

總結:很鬱悶,沒找到答案,也許我把問題想複雜了。
參考連結:http://morganchengmo.spaces.live.com/blog/cns!9950CE918939932E!1586.entry
強烈建議dudu自動把http開頭的文字加上超連結,每次我還得自己加。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.