.NET 如何定义执行相同代码的线程之间的边界
当多个线程运行同一段代码时,CLR 如何设法使它们相互超越。是 AppDomain 管理这些线程并定义不同线程之间的边界,即使它们可能作用于相同的代码(也可能是数据)?如果是这样怎么办?
TIA
When several threads are running the same piece of code, how CLR manages to keep them overstepping each other. Is it the AppDomain that manages these threads and define boundaries between different threads even though they might be acting on same code ( and possibly data)? If so how?
TIA
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
简单的;对于方法变量(不包括捕获的变量、迭代器块等),变量位于堆栈上。每个线程都有不同的堆栈。这与单线程上的递归方法没有什么不同 - 方法变量在每次调用时都是单独且独立的。
对于堆上的对象...不是!!。无界限;没有保护。如果您不正确同步等,您将损坏您的数据。
简而言之,这是你的工作。
Simple; for method variables (excluding captured variables, iterator blocks, etc), the variables are on the stack. Each thread has a different stack. This is no different to a recursive method on a single thread - the method variables are separate and independent per call.
For objects on the heap... it doesn't!!. No boundaries; no protection. If you don't correctly synchronize etc, you will corrupt your data.
In short, this is your job.
它是操作系统的实现细节。 Windows 维护每个线程的处理器上下文。该上下文包含处理器寄存器状态的副本。对您的问题而言真正重要的是 EIP(指令指针)和 ESP(堆栈指针)。指令指针跟踪线程执行的机器代码指令。堆栈指针跟踪当前执行方法的激活帧。每个线程都有自己的堆栈。
由于每个线程都有自己的指令指针,因此它们可以独立于其他线程执行自己的代码。拥有自己的堆栈可确保线程不能破坏彼此的局部变量。您的机器有数百个线程同时运行。它们轮流在可用的 CPU 内核上执行代码一段时间。操作系统的工作就是让它工作,每当它运行一段时间或阻塞时,它就会将处理器状态保存在线程上下文中,并且是时候让另一个线程轮流使用了。恢复该线程只需将状态从保存的上下文复制回处理器。当它被打断时,它会从中断处继续。
一旦线程开始访问所有线程共享的内存,线程就会变得棘手。在 .NET 程序中,这是存储在垃圾收集堆上的任何内容以及任何静态变量。需要协调一个写入此类内存的线程和读取同一内存的其他线程。 lock 关键字是实现此目的的主要方法之一。
AppDomain 的相关性在于,每个 AppDomain 都有自己的垃圾收集堆和“加载器堆”(存储静态变量值的位置)。这可以防止线程完全相互干扰。它与进程相当,没有进程的相关操作系统成本。这在 Windows 上相当高。 AppDomains 对于自定义 CLR 主机(例如 ASP.NET 和 SQL Server)非常重要。它们有助于隔离客户端请求,这样,比如说,一个因未处理的异常而爆炸的网页请求也不会破坏所有其他请求的状态。
It is an operating system implementation detail. Windows maintains the processor context for each thread. That context contains a copy of the state of the processor registers. Really important ones that matter to your question is EIP, the Instruction Pointer, and ESP, the Stack Pointer. The instruction pointer keeps track of the machine code instructions that are executed by the thread. The stack pointer keeps track of the activation frame of the currently executing method. Every thread has its own stack.
Since each thread has its own instruction pointer, they can each execute their own code, independent of other threads. Having their own stack ensures that threads cannot stomp each others local variables. Your machine has hundreds of threads running at the same time. They take turns executing code for a while on an available CPU core. It's the operating system's job to make that work, it saves the processor state in the thread context whenever it has been running for a while, or blocks, and it is time for another thread to get a turn. Resuming that thread simply involves copying the state back from the saved context to the processor. And it continues where it left off when it was interrupted.
Threading gets tricky once threads start to access memory that's shared by all threads. In a .NET program, that's anything that's stored on the garbage collected heap as well as any static variables. Having one thread that writes such memory and other threads reading the same memory needs to be orchestrated. The lock keyword is one of the primary ways to do this.
The relevance of an AppDomain is that each one has its own garbage collected heap and 'loader heap' (the place where static variable values are stored). Which prevents threads from stomping on each other completely. It is quite equivalent to a process, without the associated operating system cost of a process. Which is quite high on Windows. AppDomains are important on custom CLR hosts, like ASP.NET and SQL Server. They help isolating client requests so that, say, one web page request that bombs with an unhandled exception cannot also corrupt the state of all other requests.