統一的線程異常處理

來源:互聯網
上載者:User

在一個Service程式中, 通常都會有多個Worker線程,它們可能單獨運行, 也可能在一個ThreadPool中運行。為了不至於使Worker線程的未處理異常導致主程式的崩潰,我們需要對所有的背景工作執行緒以一種一致的方式處理異常,例如通知主線程,然後根據不同的異常做不同的處理,最後優雅地停止該有問題的線程。 例如以下程式:

static void Main(string[] args){    Thread thread1 = new Thread((ThreadStart)Worker_1);    thread1.Start();    Thread thread2 = new Thread((ThreadStart)Worker_2);    thread2.Start();    thread1.Join();    thread2.Join();}static void Worker_1(){    try    {        // Do something here.    }    catch (Exception e)    {        // TODO, handler exception,        // Notify the main thread and stop this thread gracefully.    }}static void Worker_2(){    try    {        // Do something here.    }    catch (Exception e)    {        // TODO, handler exception,        // Notify the main thread and stop this thread gracefully.    }}

在該程式中,我們有 Worker_1 和 Worker_2兩個背景工作執行緒,它們有相同的異常處理過程。但是問題是,當任務的種類多了起來,如Worker_3, Worker_4, 所有的這樣的線程函數都要做相同的異常處理,就導致了不必要的重複,並且很容易遺忘。怎樣去除這種重複呢?首先想到的是一個方案是,提供一個輔助函數,它接受一個Action作為參數:

static void SafeThread(Action action){    try    {        action();    }    catch (Exception e)    {        // TODO, handler exception,        // Notify the main thread and stop this thread gracefully.    }}

然後Worker_1 可以這麼寫:

static void Worker_1(){    SafeThread(delegate    {        // Do something here.    });}

這樣是能簡化一些。但這種做法會使原來的Worker方法有一個奇怪的封裝,而且依然要求我們對每一個Worker做同樣的處理。既然Thread的建構函式接受一個 ThreadStart的參數,我們能不能把一個原始的直接的Worker 方法(也是 ThreadStart類型)轉換為一個可以處理異常的 ThreadStart 類型呢? 是可以的。首先我們定義這個轉換函式如下:

static ThreadStart SafeThread(ThreadStart threadStart){    return () =>    {        try        {            threadStart();        }        catch (Exception e)        {            // TODO, handler exception,            // Notify the main thread and stop this thread gracefully.        }    };}

 

那麼我們的Worker線程會很直接:

static void Worker_1(){    Console.WriteLine("Worker 1");    // Do something here.}static void Worker_2(){    Console.WriteLine("Worker 2");    // Do something here.}

而主程式則需要稍加改動,但也非常簡單:

static void Main(string[] args){    Thread thread1 = new Thread(SafeThread(Worker_1));    thread1.Start();    Thread thread2 = new Thread(SafeThread(Worker_2));    thread2.Start();    thread1.Join();    thread2.Join();}

 

這對線程函數的編寫者來說, 減輕了很多負擔, 也不至於會遺漏掉某個線程沒被處理。做一次簡單的搜尋就可以解決問題。

對於接受一個參數的線程(ParameterizedThreadStart)和線程池線程 (WaitCallback),我們又該如何處理呢?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.