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.
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; } } }
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?
Variables are containers for storing data values. In C, there are different types of variables (defined with different keywords), for example: int - stores integers (whole numbers), without decimals, such as 123 or -123. float - stores floating point numbers, with decimals, such as 19.99 or -19.99.
Accessing a function. The user-defined function should be called explicitly using its name and the required arguments to be passed. The compiler refers to the function prototype to check whether the function has been called correctly.
Calling a C function (aka invoke a function)variable = function_name ( args, ...); The function name must match exactly the name of the function in the function prototype. The args are a list of values (or variables containing values) that are "passed" into the function.
For the definitive answer go to the spec. :)
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."
So that confirms that s_Initialized will never be unstable, and that read and writes to primitve types smaller than 32 bits are atomic.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With