数据库读写锁的实现(C++)

一、基本概念

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

四、程序运行

程序数据输入如下:

运行后得到结果如下:

数据库读写锁的实现(C++),布布扣,bubuko.com

时间: 2024-08-28 02:58:44

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

数据库读写锁

参考文章:https://www.cnblogs.com/yelbosh/p/5813865.html 在MVCC中,读操作可以分成两类,快照读(Snapshot read)和当前读(current read).快照读,读取的是记录的可见版本(可能是历史版本,即最新的数据可能正在被当前执行的事务并发修改),不会对返回的记录加锁:而当前读,读取的是记录的最新版本,并且会对返回的记录加锁,保证其他事务不会并发修改这条记录.在MySQL InnoDB中,简单的select操作,如 select * f

ReentrantReadWriteLock读写锁的使用2

本文可作为传智播客<张孝祥-Java多线程与并发库高级应用>的学习笔记. 这一节我们做一个缓存系统. 在读本节前 请先阅读 ReentrantReadWriteLock读写锁的使用1 第一版 public class CacheDemo { private Map<String, Object> cache = new HashMap<String, Object>(); public static void main(String[] args) { CacheDem

读写锁ReadWriteLock和缓存实例

读写锁:多个读锁不互斥,读锁与些锁互斥,写锁与写锁互斥.即:读的时候不允许写,写的时候不允许读,可以同时读. synchronized关键字和普通的Lock构造的锁,会造成读与读之间的互斥,因此读写锁可提高性能. 例子1:三个线程同时对一个共享数据进行读写. import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantRea

java5读写锁用法

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可.如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁.总之,读的时候上读锁,写的时候上写锁! 三个线程读数据,三个线程写数据示例:可以同时读,读的时候不能写,不能同时写,写的时候不能读.读的时候上读锁,读完解锁:写的时候上写锁,写完解锁.注意finally解锁. package com.ljq.test.threa

比较synchronized和读写锁

一.科普定义 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用,在这就不多说只做几点归纳: Java提供这个关键字,为防止资源冲突提供的内置支持.当任务执行到被synchronized保护的代码片段的时候,它检查锁是否可用,然后获取锁,执行代码,释放锁. 常用这个关键字可以修饰成员方法和代码块 2)读写锁 我们对数据的操作无非两种:“读”和“写”,试想一个这样的

名不符实的读写锁

有一种单一写线程.多个读线程并发的场景,比方測量数据的读取与更新,消费者会比較多.生产者仅仅有一个.下面图为例: 左側是一种经典的解法,对数据整个操作加锁.为了一个写数据线程,于将全部读线程也进行加锁显然有点浪费了.于是提出读写锁(Reader/Writer Lock), 即使是使用了读写锁.其本质也是一样的.并且在POSIX下的pthread它的内部实现是基于mutex,所以它的开销更大.假设没有非常重的读操作来抵消它引入的开销,反而会引起性能的下降.已经多组測试数据来证明这一点.我自己也做了

用信号量和读写锁解决读者写者问题

读者写者问题是非常经典的同步问题,本文首先用信号量来解决这个问题,并结合代码分析什么是读者优先.什么是写者优先,然后给出读写锁的解决方案,并指出在Linux下读写锁的注意事项. 读者写者问题 读者写者问题描述的是这么一种情况:对象在多个线程(或者进程)之间共享,其中一些线程只会读数据,另外一些线程只会写数据.为了保证写入和读取的正确性,我们需要保证,只要有线程在写,那么其他线程不能读,否则可能读到写了一半的数据:另外,也不能有两个线程同时写,否则导致数据错乱.当然,多个线程是可以同时读数据. 读

读写锁:ReadWriteLock

http://my.oschina.net/20076678/blog/173165 一.在JDK文档中关于读写锁的相关说明 ReadWriteLock 维护了一对相关的 锁 ,一个用于只读操作,另一个用于写入操作.只要没有 writer, 读取锁 可以由多个 reader 线程同时保持. 写入锁 是独占的.  所有 ReadWriteLock 实现都必须保证 writeLock 操作的内存同步效果也要保持与相关 readLock 的联系.也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所

Java缓存和读写锁

先说最常见的一道面试题: hibernate 中的load()方法和get()方法的区别 用这些代码解释最好 User user = session.load(id,User.class);        User user = session.load(id,User.class);        //缓存代理        User$Proxy extends User{            private Integer id = id;            User realUser