一、基本概念

在数据库中,对某数据的两个基本操作为写和读。分布有两种锁控制:排它锁(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的实时状态,锁表的信息随着事务的运行动态更新,反映当前的锁状态。

其数据结构例如以下图所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZnkyNDYy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

当中: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";
}
}

四、程序执行

程序数据输入例如以下:

执行后得到结果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZnkyNDYy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

数据库读写锁的实现(C++)的更多相关文章

  1. 用读写锁三句代码解决多线程并发写入文件 z

    C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...

  2. C#使用读写锁三行代码简单解决多线程并发写入文件时线程同步的问题

    (补充:初始化FileStream时使用包含文件共享属性(System.IO.FileShare)的构造函数比使用自定义线程锁更为安全和高效,更多内容可点击参阅) 在开发程序的过程中,难免少不了写入错 ...

  3. java5 ReadWriteLock用法--读写锁实现

    读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可.如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果你的代码修改数据,只能有一 ...

  4. 一道面试题比较synchronized和读写锁

    一.科普定义 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用, ...

  5. 读写锁:ReadWriteLock

    http://my.oschina.net/20076678/blog/173165   一.在JDK文档中关于读写锁的相关说明 ReadWriteLock 维护了一对相关的 锁 ,一个用于只读操作, ...

  6. <转>一道面试题比较synchronized和读写锁

    一.科普定义(原文:http://903497571.iteye.com/blog/1874752) 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步 ...

  7. java中ReentrantReadWriteLock读写锁的使用

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...

  8. 读写锁ReadWriteLock和缓存实例

    读写锁:多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥.即:读的时候不允许写,写的时候不允许读,可以同时读.      synchronized关键字和普通的Lock构造的锁,会造成读与读之间的互斥, ...

  9. ReentrantReadWriteLock读写锁的使用

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...

随机推荐

  1. 雅礼集训 Day6 T2 Equation 解题报告

    Equation 题目描述 有一棵\(n\)个点的以\(1\)为根的树,以及\(n\)个整数变量\(x_i\).树上\(i\)的父亲是\(f_i\),每条边\((i,f_i)\)有一个权值\(w_i\ ...

  2. Oracle 根据逗号分隔字符串 同时记录一波坑

    报表需要过滤掉不需要的数据,由于报表是根据零件编号来统计,需要过滤掉不合格品,只能根据关联的物料编码(零件编号)来过滤,只能通过not in来过滤,但是天真的我却用下面代码来当子查询: b.part_ ...

  3. Netapp exportfs NFS Config CLI Guide

    Netapp exportfs NFS Config CLI Guide A quick and simple Netapp NFS configuration guide with commands ...

  4. js,将日期时分秒等格式化和转化

    1.将js Date对象格式化为指定格式,添加一个原型方法 /** * 返回指定format的string * format eg:'yyyy-MM-dd hh:mm:ss' **/ Date.pro ...

  5. C/C++ 运算符 & | 运算

    C/C++中的“按位或 规则: 1|1=1 1|0=1 0|1=1 0|0=0 按位或运算 按位或运算符“|”是双目运算符.其功能是参与运算的两数各对应的二进位(也就是最后一位)相或.只要对应的二个二 ...

  6. masscan banners 不显示

    https://github.com/robertdavidgraham/masscan/issues/221

  7. Linux学习总结—缺页中断和交换技术【转】

    三.Linux缺页中断处理 转自:http://blog.csdn.net/cxylaf/article/details/1626534 1.请求调页中断: 进程线性地址空间里的页面不必常驻内存,例如 ...

  8. Java工厂模式浅析理解

    由于本人缺乏工作经验,本篇文章作为随笔,只是对工厂模式有一个简单的认识 工厂模式分为以下三种: 1:简单工厂(Simple Factory).2:工厂方法(Factory Method).3:抽象工厂 ...

  9. Appium+python自动化6-Remote远程控制【转载】

    前言 在第三篇启动app的时候有这样一行代码driver = webdriver.Remote('http://192.168.1.1:4723/wd/hub', desired_caps),很多小伙 ...

  10. 使用EventHandler传递参数

    1.MouseEventHandler和EventHandler传递参数的局限性分析 开发过程中,特别是使用自定义控件时,常常需要对一个控件的click,mouseDown,mouseUp等事件的处理 ...