是否在 .NET 安全实践中使用 Thread.Abort() 和处理 ThreadAbortException? [英] Is using Thread.Abort() and handling ThreadAbortException in .NET safe practice?

查看:21
本文介绍了是否在 .NET 安全实践中使用 Thread.Abort() 和处理 ThreadAbortException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在 C# 中开发一个多线程 Azure 辅助角色 - 创建多个线程,向它们提供请求,每个请求可能需要很长时间来处理(不是我的代码 - 我将调用一个 COM 对象来完成实际工作).

I need to develop a multithreaded Azure worker role in C# - create multiple threads, feed requests to them, each request might require some very long time to process (not my code - I'll call a COM object to do actual work).

在角色关闭时,我需要优雅地停止处理.我怎么做?看起来,如果我只是调用 Thread.Abort()ThreadAbortException 会被抛出到线程中,线程甚至可以使用 try-catch-finally(或 using) 来清理资源.这看起来很可靠.

Upon role shutdown I need to gracefully stop processing. How do I do that? Looks like if I just call Thread.Abort() the ThreadAbortException is thrown in the thread and the thread can even use try-catch-finally (or using) to clean up resources. This looks quite reliable.

困扰我的是,我的经验主要是 C++,不可能在非托管应用程序中优雅地中止线程 - 它会停止而不进行任何进一步处理,这可能会使数据处于不一致的状态.所以我有点怀疑如果我为一个繁忙的线程调用 Thread.Abort() 是否会发生类似的事情.

What bothers me is that my experience is mostly C++ and it's impossible to gracefully abort a thread in an unmanaged application - it will just stop without any further processing and this might leave data in inconsistent state. So I'm kind of paranoid about whether anything like that happens in case I call Thread.Abort() for a busy thread.

Thread.Abort() 与处理 ThreadAbortException 一起使用是否安全?如果我这样做,我应该注意什么?

Is it safe practice to use Thread.Abort() together with handling ThreadAbortException? What should I be aware of if I do that?

推荐答案

是否在 .NET 安全实践中使用 Thread.Abort() 和处理 ThreadAbortException?

Is using Thread.Abort() and handling ThreadAbortException in .NET safe practice?

TL;DR 版本:不,不是.

TL;DR version: No, isn't.

通常,当所有类型不变量(无论是否明确说明)都为真时,您是安全的.然而,许多方法会在运行时打破这些不变量,只有在最后它们再次为真时才会达到新的状态.如果线程在保持不变的状态下处于空闲状态,您会没事的,但在这种情况下,最好使用诸如事件之类的东西来通知线程正常退出(即,您不需要中止).

Generally you're safe when all type invariants (whether explicitly stated or not) are actually true. However many methods will break these invariants while running, only to reach a new state when they are again true at the end. If the thread is idle in a state with invariants held you'll be OK, but in that case better to use something like an event to signal the thread to exit gracefully (ie. you don't need to abort).

在线程中抛出的带外异常1,而在这样的不变量中,即不为真.无效,状态是问题开始的地方.这些问题包括但当然不限于相互不一致的字段和属性值(处于无效状态的数据结构)、未退出锁以及未触发表示发生更改"的事件.

An out-of-band exception1 thrown in a thread while in such a invariants-not-true, ie. invalid, state is where the problems start. These problems include, but are certainly not limited to, mutually inconsistent field and property values (data structures in an invalid state), locks not exited, and events representing "changes happened" not fired.

在许多情况下,可以在清理代码中处理这些问题(例如,一个 finally 块),但是然后考虑当 out-of-那个清理代码中发生乐队异常?这导致清理代码的清理代码.但是,该代码本身容易受到攻击,因此您需要为清理代码的清理代码进行清理代码…它永远不会结束!

In many cases it is possible to deal with these in clean up code (eg. a finally block), but then consider what happens when the out-of-band exception occurs in that clean up code? This leads to clean up code for the clean up code. But then that code is it self vulnerable so you need clean up code for the clean up code of the clean up code… it never ends!

有解决方案,但它们不容易设计(并且往往会影响您的整个设计),更难测试——如何重新创建所有案例(想想组合爆炸).两种可能的路线是:

There are solutions, but they are not easy to design (and tends to impact your whole design), and even harder to test—how to re-create all the cases (think combinatorial explosion). Two possible routes are:

  1. 处理状态副本,更新副本,然后以原子方式将当前状态交换为新状态.如果出现带外异常,则保留原始状态(并且终结器可以清理临时状态).

  1. Work on copies of state, update the copies and then atomically swap current for new state. If there is an out-of-band exception then the original state remains (and finalisers can clean up the temporary state).

这很像数据库事务的功能(尽管 RDBMS 使用锁和事务日志文件).

This is rather like the function of database transactions (albeit RDBMSs work with locks and transaction log files).

它也类似于 C++ 社区为响应 纸上质疑异常是否安全(C++ 当然没有 GC/finaliser 队列来清理丢弃的对象).参见 Herb Sutters 本周大师 #8:挑战版:异常安全"解决方案.

It is also similar to the approaches to achieving the "strong exception guarantee" developed in the C++ community in response to a paper questioning if exceptions could ever be safe (C++ of course has no GC/finaliser queue to clean up discarded objects). See Herb Sutters "Guru of the Week #8: CHALLENGE EDITION: Exception Safety" for the solution.

在实践中,除非您的状态可以封装在单个引用中,否则这很难实现.

In practice this is hard to achieve unless your state can be encapsulated in a single reference.

查看受限执行区域",但不是在这些情况下您可以做什么的限制.(MSDN 杂志有一篇介绍性文章(对主题的介绍,不是入门级),来自 .NET 2 beta 期2).

Look at "Constrained Execution Regions", but not the limitations on what you can do in these cases. (MSDN Magazine had an introductory article (introduction to the subject, not introductory level), from .NET 2 beta period2).

在实践中,如果您必须这样做,使用方法 #2 来管理 #1 下的状态更改可能是最好的方法,但是正确处理,然后验证它是正确的(并保持正确性)是.

In practice if you have to do this, using approach #2 to manage the state change under #1 is probably the best approach, but getting it right, and then validating that it is correct (and the correctness is maintained) is hard.

总结:有点像优化:规则1:不要做;规则 2(仅限专家):除非别无选择,否则不要这样做.

Summary: It's a bit like optimisation: rule 1: don't do it; rule 2 (experts only): don't do it unless you have no other option.

1 ThreadAbortException 并不是唯一的此类异常.

1 A ThreadAbortException is not the only such exception.

2 所以细节可能已经改变了.

2 So details have possibly changed.

这篇关于是否在 .NET 安全实践中使用 Thread.Abort() 和处理 ThreadAbortException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆