一、基本概念

在数据库中,对某数据的两个基本操作为写和读。分布有两种锁控制:排它锁(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. 逆向映射是干嘛的anon_vma, vma, anon_vma_chain

    逆向映射是为了从page得到进程信息,里面有三个比较重要的结构体: mm_area_struct, anon_vma_chain, anon_vma 想象一种复杂的场景 所以其实一个进程对应着很多an ...

  2. hdu 1512

    思路:用并查集即可,每次合并的时候将小的集合合并到大的集合上去.理论上的平均复杂度是n*lgn*lgn. #include<map> #include<queue> #incl ...

  3. CF911F Tree Destruction 解题报告

    CF911F Tree Destruction 题意翻译 给你一棵树,每次挑选这棵树的两个叶子,加上他们之间的边数(距离),然后将其中一个点去掉,问你边数(距离)之和最大可以是多少. 输入输出格式 输 ...

  4. 使AD域控服务器Administrator的密码永不过期方法。

    在安装完AD域后,管理员密码会42天就要更新一次,这样对测试比较不方便, 如果要让域控管理员账号密码永远不过期,就照着下面的方法执行: open a Command Prompt as the adm ...

  5. 《c程序设计语言》读书笔记-3.5-按要求进制位数字转字符串

    #include <io.h> #include <stdio.h> #include <string.h> #include <stdlib.h> # ...

  6. poj 1061 青蛙的约会 (扩展欧几里得模板)

    青蛙的约会 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status ...

  7. 信息传递(NOIP2015)(寻找最小环。。)

    原题传送门 这是一道寻找最小环的题目. 在做的时候给每一个点染色.. 防止再做已经搜过的点(优化) v[]表示是否访问的过,以及第一次访问该点的时间. u[]表示染色.. 这道题还可以用拓补排序做. ...

  8. Linux下USB驱动框架分析【转】

    转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...

  9. 【原创】DataPackage-数据库、表的区域设置和系统不一致导致处理失败

    问题描述: 最近学习Datapackage,创建完之后,部署处理但总是提示某某字段的区域设置和目标字段的区域设置不一致,具体如图: 测试发现其它的数据库表又没有这类的问题发生,甚是苦恼,搜寻了好久,后 ...

  10. Android从相册选取视频

    1. /** * 从相册中选择视频 */ private void choiceVideo() { Intent i = new Intent(Intent.ACTION_PICK, android. ...