问题描述
我一直相信如果多个线程可以访问一个变量,那么对该变量的所有读取和写入都必须受到同步代码的保护,例如锁定"语句,因为处理器可能会切换到另一个写到一半的线程.
I've been raised to believe that if multiple threads can access a variable, then all reads from and writes to that variable must be protected by synchronization code, such as a "lock" statement, because the processor might switch to another thread halfway through a write.
但是,我正在使用 Reflector 查看 System.Web.Security.Membership 并找到如下代码:
However, I was looking through System.Web.Security.Membership using Reflector and found code like this:
public static class Membership
{
private static bool s_Initialized = false;
private static object s_lock = new object();
private static MembershipProvider s_Provider;
public static MembershipProvider Provider
{
get
{
Initialize();
return s_Provider;
}
}
private static void Initialize()
{
if (s_Initialized)
return;
lock(s_lock)
{
if (s_Initialized)
return;
// Perform initialization...
s_Initialized = true;
}
}
}
为什么 s_Initialized 字段是在锁外读取的?另一个线程不能同时尝试写入它吗?变量的读写是原子的吗?
Why is the s_Initialized field read outside of the lock? Couldn't another thread be trying to write to it at the same time? Are reads and writes of variables atomic?
推荐答案
有关最终答案,请参阅规范.:)
For the definitive answer go to the spec. :)
CLI 规范的第 I 部分第 12.6.6 节规定:当对一个位置的所有写访问都被写入时,符合标准的 CLI 应保证对不大于本机字大小的正确对齐的内存位置的读写访问是原子的.相同的尺寸."
Partition I, Section 12.6.6 of the CLI spec states: "A conforming CLI shall guarantee that read and write access to properly aligned memory locations no larger than the native word size is atomic when all the write accesses to a location are the same size."
这证实了 s_Initialized 永远不会不稳定,并且读取和写入小于 32 位的原始类型是原子的.
So that confirms that s_Initialized will never be unstable, and that read and writes to primitve types smaller than 32 bits are atomic.
特别是double
和long
(Int64
和UInt64
)不是 保证在 32 位平台上是原子的.您可以使用 Interlocked
类上的方法来保护这些.
In particular, double
and long
(Int64
and UInt64
) are not guaranteed to be atomic on a 32-bit platform. You can use the methods on the Interlocked
class to protect these.
此外,虽然读取和写入是原子的,但存在加法、减法、自增和自减原始类型的竞争条件,因为它们必须被读取、操作和重写.互锁类允许您使用 CompareExchange
和 Increment
方法来保护这些.
Additionally, while reads and writes are atomic, there is a race condition with addition, subtraction, and incrementing and decrementing primitive types, since they must be read, operated on, and rewritten. The interlocked class allows you to protect these using the CompareExchange
and Increment
methods.
互锁会创建一个内存屏障,以防止处理器重新排序读取和写入.在这个例子中,锁创建了唯一需要的屏障.
Interlocking creates a memory barrier to prevent the processor from reordering reads and writes. The lock creates the only required barrier in this example.
这篇关于在 C# 中访问变量是原子操作吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!