一、基本概念

在数据库中,对某数据的两个基本操作为写和读。分布有两种锁控制:排它锁(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. 网络namespace

    sduo sysctl -w net.ipv4.conf.all.forwarding=1 sudo iptables -t nat -A  POSTROUTING -s 172.18.0.0/24 ...

  2. task [最大权闭合子图]

    题面 思路 其实仔细读透就发现,是一个最大权闭合子图的模型 套进网络流里面就挺好做的了 可以选择重载这道题里面的一些运算(加减,取最小值),这样比较方便 Code #include<iostre ...

  3. [转]Linux下阅读源代码:(g)vim+Taglist+ctags

      Linux下阅读源代码的方法很多,聪明人从标题应该就可以知道,需要(g)vim+Taglist+ctags.3者配合,真是珠联璧合,功力无限啊! vim/gvim什么是vim/gvim,如果看官连 ...

  4. 【IDEA】IDEA下maven项目无法提示和使用EL表达式的解决办法

    今天在IDEA创建web项目之后发现无法使用EL和JSTL, 一.如果JSP中无法自动提示EL表达式,比如${pageContext.request.contextPath},可在pom.xml的&l ...

  5. JS与jQuery中html-与-text方法的区别

    所有的实例均用下面的html <div id="id0"> <div id="id1"> 直接text <p> <sp ...

  6. 基于Xen实现一种domain0和domainU的应用层数据交互高效机制

    项目里有一个需求,domain0的应用层需要定时给domainU(hvm windows)的应用层传递一块数据,原来的方案是在domainU的应用层架设一个http服务器,监听在某个端口,然后需要塞数 ...

  7. c/c++中const用法总结

    1.修饰常量时: const int temp1;  //temp1为常量,不可变 int const temp2;  //temp2为常量,不可变 2.修饰指针时: 主要看const在*的前后,在前 ...

  8. 在OpenResty中使用淘宝的concat进行css和js合并,同时支持GZIP静态压缩

    =======================================================================================cd /usr/local ...

  9. VS2010安装包制作

    最近对软件安装包制作研究了一下,下面记录了一种比较简单,不用写代码的方法. 1.New Project---->Other Project Types ---->Visual Studio ...

  10. C# 查看本机安装的NET Framework 版本

    https://docs.microsoft.com/zh-cn/dotnet/framework/migration-guide/how-to-determine-which-versions-ar ...