Global variables and threads

2019-06-14 05:47发布

问题:

If I have a global counter and I have two threads that are each incrementing it 100 times in a loop, why is it possible that I can have a value other than 200? I don't see how accessing the variable is nonatomic.

回答1:

That is because for most environments, incrementing a memory location is not an atomic operation.

The sequence of events would be something like

  • The compiler places the value 0 at the memory address 0xABCD
  • Thread 1 reads 0xABCD into a register and increments the register value
  • Thread 1 is interrupted by Thread 2
  • Thread 2 reads the value 0 from the memory address 0xABCD into a register
  • Thread 2 increments the value in the register
  • Thread 2 writes the value from the register to 0xABCD
  • Thread 2 reads the value 1 from 0xABCD, increments the register, and writes back again
  • Thread 1 resumes
  • Thread 1 writes the value from its register, 1, to 0xABCD, overwriting the value 2 that Thread 2 had previously written there.

To ensure a consistent result, you must make the increment operation atomic. This is often done by placing a thread lock around the increment operation. For example, in C# that might look like

object mylock = new object();
...
lock (mylock) 
{ 
    myInt++;
}

Alternatively, in the .NET environment, one could use Interlocked.Increment

http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx

Other environments have similar constructs.

The best reference I have ever come across for threading in the .NET environment (but is a useful read no matter what your environment) is the following

http://www.albahari.com/threading/