一、基本概念
在資料庫中,對某資料的兩個基本操作為寫和讀,分布有兩種鎖控制:排它鎖(X鎖)、共用鎖定(S鎖)。
排它鎖(x鎖):若事務T對資料D加X鎖,則其它任何事務都不能再對D加任何類型的鎖,直至T釋放D上的X鎖;
一般要求在修改資料前要向該資料加排它鎖,所以排它鎖又稱為寫鎖。
共用鎖定(s鎖):若事務T對資料D加S鎖,則其它事務只能對D加S鎖,而不能加X鎖,直至T釋放D上的S鎖;
一般要求在讀取資料前要向該資料加共用鎖定, 所以共用鎖定又稱讀鎖。
程式所收到的請求包括以下五種:Start、End、XLock、SLock、Unlock
Start:開啟相應的事件請求
End: 關閉相應的事件請求
XLock: 對資料對象D添加X鎖,進行寫操作(當事件以對資料A加入S鎖時,此時可升級為X鎖)
SLock: 對資料對象D添加S鎖,進行讀操作
Unlock: 對資料對象D進行解鎖(對資料D的X/S鎖解除綁定,並檢查等待隊列)
本程式並不進行死結檢測以及死結預防,對於等待隊列採取FIFO原則進行。
二、資料結構
讀寫鎖維護一個資料D的狀態表,標記當前資料D的即時狀態,鎖表的資訊隨著事務的執行動態更新,反映當前的鎖狀態。
其資料結構如所示:
其中:mObjectList:為map結構的對象樹,可方便快速尋找相應對象。
objectName:為對象資料D的名稱
curXLockTrans: 為當前寫操作的事件
waitingTransList: 為寫等待隊列
shareList: 為共用集(當curXLockTrans不為空白時,變為共用等待隊列)
事件ID的資料結構如下:
其中:mTransId: 為map結構的事件樹,可以快速的尋找相應事件
tranId: 為事件名稱
curLockObjList: 為此事件目前所操作的對象列表
三、原始碼
本程式為所的鎖管理介面,所以封裝成類,方便程式調用。程式源碼可以點擊這裡下載。
資料結構如下:
class LMer {private: struct object { string objectName; string curXLockTrans; queue<string> waitingTransList; set<string> shareList; }; struct transId { string tranId; set<object*> curLockObjList; }; map<string, object*> mObjectList; map<string, transId*> mTransId;public: LMer(){} string LMer::handleInput(vector<string>& vInput); void LMer::handleAction(string sAction, transId* trId, object* obj, string& result); void LMer::diviTransID(transId* trId, object* pObj, string& result);};
邏輯結構實現如下:
string LMer::handleInput(vector<string>& vInput){ string result = ""; //二參數輸入 if (vInput.size() == 2) { //進程存在,進入下一步 map<string, transId*>::iterator transIt = mTransId.find(vInput[1]); if (transIt != mTransId.end()) { //是否結束事件(結束事件隊列中所有事件) if (vInput[0] == "End") { result += "\tTransaction "+ vInput[1] +" ended\n\t\t\t"; //解除綁定進程所有事物 set<object*>::iterator obj_index; while(transIt->second->curLockObjList.size() != 0) { obj_index = transIt->second->curLockObjList.begin(); diviTransID(transIt->second, *obj_index, result); } //清空請求事件 mTransId.erase(transIt); } } else if(vInput[0] == "Start")//為start,創立進程 { transId* pTransId = new transId(); pTransId->tranId = vInput[1]; //將此進程加入進程樹中 mTransId[vInput[1]] = pTransId; result += "Transaction " + vInput[1] +" started\n"; } } else //三參數輸入 { //建立新操作對象 if(mObjectList.find(vInput[2]) == mObjectList.end()) { object* pObjectIndex = new object(); pObjectIndex->objectName = vInput[2]; pObjectIndex->curXLockTrans = ""; mObjectList[vInput[2]] = pObjectIndex; } if (vInput[0] == "Unlock") { //解鎖trans->obj diviTransID(mTransId[vInput[1]], mObjectList[vInput[2]], result); } else//進行常規處理(Xlock、Slock) { //進行處理 handleAction(vInput[0], mTransId[vInput[1]], mObjectList[vInput[2]], result); } } return result;}void LMer::handleAction(string sAction, transId* trId, object* obj, string& result){ //檢查是否有佔用 if (sAction == "SLock") { if (obj->curXLockTrans == "") { obj->shareList.insert(trId->tranId); trId->curLockObjList.insert(obj); result += "S-Lock granted to "+ trId->tranId +"\n"; } else//被佔用 { obj->shareList.insert(trId->tranId); result += "Waiting for lock (X-lock held by: "+ obj->curXLockTrans +")\n"; } } else if(sAction == "XLock") { //未有寫操作 if (obj->curXLockTrans == "") { int shareNum = obj->shareList.size(); if (shareNum > 1) { string sTemp = ""; for (set<string>::iterator it_index = obj->shareList.begin(); it_index != obj->shareList.end(); it_index++) { sTemp += " " + *it_index; } obj->waitingTransList.push(trId->tranId); result += "Waiting for lock (S-lock held by:" + sTemp + "\n"; } else if (shareNum == 1) { //update if (*(obj->shareList.begin()) == trId->tranId) { obj->curXLockTrans = trId->tranId; obj->shareList.clear(); result += "Upgrade to XLock granted\n"; } else { obj->waitingTransList.push(trId->tranId); result += "Waiting for lock (S-lock held by:" + *(obj->shareList.begin()) + ")\n"; } } else if (shareNum == 0) { obj->curXLockTrans = trId->tranId; trId->curLockObjList.insert(obj); result += "XLock granted\n"; } } else//當前存在寫操作 { obj->waitingTransList.push(trId->tranId); result += "Waiting for lock (X-lock held by: "+ obj->curXLockTrans +")\n"; } }}void LMer::diviTransID(transId* trId, object* pObj, string& result){ if(pObj->curXLockTrans != "") { //對寫操作解除綁定 if (pObj->curXLockTrans == trId->tranId) { pObj->curXLockTrans = ""; trId->curLockObjList.erase(pObj); result += "Lock released\n\t\t\t"; } else { result += "I can not find the transaction.\n\t\t\t"; } }//對共用讀集合解除綁定 else { set<string>::iterator shareIndex = pObj->shareList.find(trId->tranId); if (shareIndex != pObj->shareList.end()) { pObj->shareList.erase(shareIndex); trId->curLockObjList.erase(pObj); result += "Lock released\n\t\t\t"; } else { result += "I can not find the transaction.\n\t\t\t"; } } //查看寫等待隊列 if (pObj->waitingTransList.size() != 0) { pObj->curXLockTrans = pObj->waitingTransList.front(); pObj->waitingTransList.pop(); result += "X-Lock on "+ pObj->objectName +" granted to "+ pObj->curXLockTrans +"\n"; }//查看共用隊列 else if (pObj->shareList.size() != 0) { string temp = ""; for(set<string>::iterator it_index = pObj->shareList.begin(); it_index != pObj->shareList.end(); it_index++) { temp += " " + *it_index; } result += "S-Lock on "+ pObj->objectName +" granted to "+ temp +"\n"; }}
四、程式運行
程式資料輸入如下:
運行後得到結果如下: