您的位置:首页 > 其它

统一的线程异常处理

2009-12-26 22:48 369 查看
在一个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),我们又该如何处理呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: