Design and Implementation of user space locks
Yesterday we completed the implementation of the lock-free queue, and then thought about the lock principle. The core of the lock is to ensure that a variable needs to be updated atomically. For example, we use a bool x, indicates the lock. When we obtain the lock, we need to ensure that the lock can be read and updated only by one of multiple threads at the same time, logically, there is the following code:
Bool GetLock (bool & x ){
If (x ){
X = false;
Return true;
}
Return false;
}
However, reading and updating are not atomic operations. If both threads find that x is true at the same time, but no thread has updated x, two threads update x at the same time, that is, two threads update the lock status at the same time. This is because the reading and updating of x is not atomic. There is a CMPXCHG command in X86, and an InterLockCompareExchange API in Windows can run such atomic operations. That is to say, we can use these two atomic operations to implement the lock. The following code is used:
# Include
# Pragma comment (lib, "kernel32.lib") class USLock {// user space lockpublic: USLock () {LockData = new int (1 );}~ USLock () {delete LockData;} public: bool Get () {return (InterlockedCompareExchange (LONG *) LockData, 0, 1);} void Release () {* LockData = 1;} private: int * LockData;}; dword winapi cs (void * lpAram); # include
# Include
Using namespace std; deque
Q; USLock lock; int main () {HANDLE hThread [2]; for (int I = 0; I <2; ++ I) {hThread [I] = :: createThread (NULL, 0, CS, (void *) I, 0, NULL);}: WaitForMultipleObjects (2, hThread, true, INFINITE );} dword winapi cs (void * lpAram) {while (true) {if (! LpAram) {// production for (int I = 0; I <1000;) {if (lock. get () {q. push_front (I ++); lock. release () ;}:: Sleep (rand () % 1000);} return 0 ;}else {if (lock. get () {// consume if (! Q. empty () {cout <
The following is a piece of test code. If you are interested, you can check it.