用戶空間鎖的設計與實現

昨天完成了無鎖隊列的實現,然後思考了一下鎖的原理,鎖的核心無非是保證有一個變量需要被原子性地更新,比如,我們用一個bool x,表示鎖,當我們獲取鎖的時候,我們需要保證的是鎖能夠只在同一時間被多個線程中的一個線程去讀取和更新,在邏輯上有如下的代碼:
bool GetLock(bool& x){
        if(x){
                x= false;
                return true;
        }
        return false;
}

然而,這裏面的讀取和更新不是原子操作的,如果兩個線程同時發現了x是true,但是,還沒有一個線程更新了x,此時,就會有兩個線程同時更新了x,也就是有兩個線程同時更新了鎖的狀態,造成這種原因在於x的讀取和更新不是原子性的。X86裏面有個CMPXCHG 指令,Windows 裏面有個InterLockCompareExchange API都能運行這種原子性的操作,也就是說,我們可以利用這兩個原子操作來完成鎖的實現。以下是代碼


#include <windows.h>
#pragma comment(lib, "kernel32.lib")

class USLock{//user space lock
public:
	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 <queue>
#include <iostream>
using namespace std;

deque<int> 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){//生產
			for(int i= 0; i< 1000; ){
				if(lock.Get()){
					q.push_front(i++);
					lock.Release();
				}
				::Sleep(rand()%1000);
			}
			return 0;
		}else{
			if(lock.Get()){//消費
				if(!q.empty()){
					cout<<q.back();
					q.pop_back();
				}
				lock.Release();
			}
		}
		::Sleep(rand()%1000);
	}
	return 0;
}

後面寫的是一段測試代碼,有興趣的同學可以看看。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章