多线程未处理的异常
我正在开展一个项目,该项目将启动多个独立流程。我希望它们能够被隔离到这样的程度:如果其中一个意外失败,其他人将继续运行而不会受到影响。我尝试过使用 AppDomains 进行 POC(粘贴在下面)来测试这一点,但它仍然会导致整个父应用程序崩溃。
我采取了错误的方法吗?如果是这样,我应该做什么?如果不是,我做错了什么?
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
Thread[] threads = new Thread[15];
for (int i = 0; i < 15; i++)
{
AppDomain domain = AppDomain.CreateDomain("Test" + i);
domain.UnhandledException += new UnhandledExceptionEventHandler(domain_UnhandledException);
domain.
Test test = domain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, "ConsoleApplication1.Test") as Test;
Thread thread = new Thread(new ParameterizedThreadStart(test.DoSomeStuff));
thread.Start(rand.Next());
Console.WriteLine(String.Format("Thread #{0} has started", i));
threads[i] = thread;
}
for (int i = 0; i < 15; i++)
{
threads[i].Join();
Console.WriteLine(String.Format("Thread #{0} has finished", i));
}
Console.ReadLine();
}
static void domain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("UNHANDLED");
}
}
public class Test : MarshalByRefObject
{
public void DoSomeStuff(object state)
{
int loops = (int)state;
for (int i = 0; i < loops; i++)
{
if (i % 300 == 0)
{
// WILL break
Console.WriteLine("Breaking");
int val = i / (i % 300);
}
}
}
}
编辑
请注意,“测试”类非常简化。实际的实现将极其复杂,并且在异常处理方面很可能存在差距。
I am working on a project that will kick off multiple independent processes. I would like them to be isolated to the point that if one fails unexpectedly, the others will continue on without being impacted. I have tried a POC (pasted below) to test this using AppDomains but it still crashes the entire parent application.
Am I taking the wrong approach? If so, what should I be doing? If not, what am I doing wrong?
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
Thread[] threads = new Thread[15];
for (int i = 0; i < 15; i++)
{
AppDomain domain = AppDomain.CreateDomain("Test" + i);
domain.UnhandledException += new UnhandledExceptionEventHandler(domain_UnhandledException);
domain.
Test test = domain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, "ConsoleApplication1.Test") as Test;
Thread thread = new Thread(new ParameterizedThreadStart(test.DoSomeStuff));
thread.Start(rand.Next());
Console.WriteLine(String.Format("Thread #{0} has started", i));
threads[i] = thread;
}
for (int i = 0; i < 15; i++)
{
threads[i].Join();
Console.WriteLine(String.Format("Thread #{0} has finished", i));
}
Console.ReadLine();
}
static void domain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("UNHANDLED");
}
}
public class Test : MarshalByRefObject
{
public void DoSomeStuff(object state)
{
int loops = (int)state;
for (int i = 0; i < loops; i++)
{
if (i % 300 == 0)
{
// WILL break
Console.WriteLine("Breaking");
int val = i / (i % 300);
}
}
}
}
EDIT
Please note that the "Test" class is extremely simplified. The actual implimentation would be extremely complex and have a very likely gap in exception handling.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您不需要单独的应用程序域。您所需要做的就是捕获 Test 类的
DoSomeStuff
成员中的异常。因此,如果这些线程之一处理自己的异常,那么应用程序的其余部分可以继续运行。You don't need separate AppDomains. All you need to do is to catch exceptions in the
DoSomeStuff
member of the Test class. Thus if one of these threads handles its own exception, then rest of your app can continue running.您必须在引发异常的线程中捕获异常,没有办法解决这个问题。接下来您需要做的可能是将异常序列化回主应用程序域,以便它能够识别它。毕竟,它启动线程来完成某种工作,但该工作尚未完成。应该对此采取一些措施。
您正在模拟的是 SQL Server 和 ASP.NET 的工作方式。他们有一个非常好的执行模型。它们接受来自客户端计算机的执行工作的请求。如果这个请求失败了,他们可以奢侈地发回一条“抱歉,它不起作用”的消息。然后耸耸肩,就像它从未发生过一样,得到了应用程序域的良好支持。
将其留给客户端计算机来处理。顺便说一句,经常需要人类的帮助。很简单,但它们这样设计并不是偶然的。真正模仿这种执行模式还需要找到其他人来处理痛苦。那很难。
You have to catch the exception in the thread that raised it, there's no way around that. What you need to do next is probably serialize the exception back to the primary appdomain so it is aware of it. After all, it set off the thread to get some kind of job done and that job wasn't completed. Something ought to be done about that.
What you are emulating is the way that SQL Server and ASP.NET work. They have a very nice execution model. They accept requests to perform work from client machines. If that request bombs, they have the luxury of sending back a "sorry, it didn't work" message back. And shrug it off like it never happened, so nicely supported by appdomains.
Leaving it up to the client machine to deal with that. Not infrequently requiring the assistance of a human btw. Easy peasy, but it wasn't an accident they were designed that way. Truly emulating this execution model also requires finding somebody else to deal with the misery. That's difficult.