Threads synchronization. How exactly lock makes access to memory 'correct'?

后端 未结 5 1177
清歌不尽
清歌不尽 2020-12-29 09:41

First of all, I know that lock{} is synthetic sugar for Monitor class. (oh, syntactic sugar)

I was playing with simple mul

5条回答
  •  失恋的感觉
    2020-12-29 10:26

    why exactly does lock(ms_Lock) { ms_Counter += 1; } make the program completely correct but lock(ms_Lock) {}; ms_Counter += 1; only almost correct?

    Good question! The key to understanding this is that a lock does two things:

    • It causes any thread that contests the lock to pause until the lock can be taken
    • It causes a memory barrier, also sometimes called a "full fence"

    I do not totally understand how lockng some arbitrary object prevents other memory from being cached in registers/CPU cache, etc

    As you note, caching memory in registers or the CPU cache can cause odd things to happen in multithreaded code. (See my article on volatility for a gentle explanation of a related topic..) Briefly: if one thread makes a copy of a page of memory in the CPU cache before another thread changes that memory, and then the first thread does a read from the cache, then effectively the first thread has moved the read backwards in time. Similarly, writes to memory can appear to be moved forwards in time.

    A memory barrier is like a fence in time that tells the CPU "do what you need to do to ensure that reads and writes that are moving around through time cannot move past the fence".

    An interesting experiment would be to instead of an empty lock, put a call to Thread.MemoryBarrier() in there and see what happens. Do you get the same results or different ones? If you get the same result, then it is the memory barrier that is helping. If you do not, then the fact that the threads are being almost synchronized correctly is what is slowing them down enough to prevent most races.

    My guess is that it is the latter: the empty locks are slowing the threads down enough that they are not spending most of their time in the code that has a race condition. Memory barriers are not typically necessary on strong memory model processors. (Are you on an x86 machine, or an Itanium, or what? x86 machines have a very strong memory model, Itaniums have a weak model that needs memory barriers.)

提交回复
热议问题