`
阿尔萨斯
  • 浏览: 4332898 次
社区版块
存档分类
最新评论

系统程序员成长计划-并发(四)(下)

 
阅读更多

读写锁

读写锁在加锁时,要区分是为了读而加锁还是为了写而加锁,所以和递归锁不同的是,它无法兼容Locker接口了。不过为了做到不依赖于特定平台,我 们可以利用Locker的接口来抽象锁的实现。利用现有的锁来实现读写锁。读写锁的可变的部分已经被Locker隔离了,所以读写锁本身不需要做成接口。 它只是一个普通对象而已:

struct _RwLocker;
typedef struct _RwLocker RwLocker;

RwLocker* rw_locker_create(Locker* rw_locker, Locker* rd_locker);

Ret rw_locker_wrlock(RwLocker* thiz);
Ret rw_locker_rdlock(RwLocker* thiz);
Ret rw_locker_unlock(RwLocker* thiz);

void rw_locker_destroy(RwLocker* thiz);

o 创建读写锁

RwLocker* rw_locker_create(Locker* rw_locker, Locker* rd_locker)
{
RwLocker* thiz = NULL;
return_val_if_fail(rw_locker != NULL && rd_locker != NULL, NULL);

thiz = (RwLocker*)malloc(sizeof(RwLocker));
if(thiz != NULL)
{
thiz->readers = 0;
thiz->mode = RW_LOCKER_NONE;
thiz->rw_locker = rw_locker;
thiz->rd_locker = rd_locker;
}

return thiz;
}

读写锁的基本要求是:写的时候不允许任何其它线程读或者写,读的时候允许其它线程读,但不允许其它线程写。所以在实现时,写的时候一定要加锁,第一 个读的线程要加锁,后面其它线程读时,只是增加锁的引用计数。我们需要两个锁:一个锁用来保存被保护的对象,一个锁用来保护引用计数。

o 加写锁

Ret rw_locker_wrlock(RwLocker* thiz)
{
Ret ret = RET_OK;
return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

if((ret = locker_lock(thiz->rw_locker)) == RET_OK)
{
thiz->mode = RW_LOCKER_WR;
}

return ret;
}

加写锁很简单,直接加保护受保护对象的锁,然后修改锁的状态为已加写锁。后面其它的线程想写,就会这个锁上等待,如果想读也要等待(见后面)。

o 加读锁

Ret rw_locker_rdlock(RwLocker* thiz)
{
Ret ret = RET_OK;
return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

if((ret = locker_lock(thiz->rd_locker)) == RET_OK)
{
thiz->readers++;
if(thiz->readers == 1)
{
ret = locker_lock(thiz->rw_locker);
thiz->mode = RW_LOCKER_RD;
}
locker_unlock(thiz->rd_locker);
}

return ret;
}

先尝试加保护引用计数的锁,增加引用计数。如果当前线程是第一个读,就要去加保护受保护对象的锁。如果此时已经有线程在写,就等待直到加锁成功,然后把锁的状态设置为已加读锁,最后解开保护引用计数的锁。

o 解锁

Ret rw_locker_unlock(RwLocker* thiz)
{
Ret ret = RET_OK;
return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

if(thiz->mode == RW_LOCKER_WR)
{
thiz->mode == RW_LOCKER_NONE;
ret = locker_unlock(thiz->rw_locker);
}
else
{
assert(thiz->mode == RW_LOCKER_RD);
if((ret = locker_lock(thiz->rd_locker)) == RET_OK)
{
thiz->readers--;
if(thiz->readers == 0)
{
thiz->mode == RW_LOCKER_NONE;
ret = locker_unlock(thiz->rw_locker);
}
locker_unlock(thiz->rd_locker);
}
}

return ret;
}

解锁时根据状态来决定,解写读直接解保护受保护对象的锁。解读锁时,先要加锁保护引用计数的锁,引用计数减一。如果自己是最后一个读,才解保护受保护对象的锁,最后解开保护引用计数的锁。

从上面读写锁的实现,我们可以看出,读写锁要充分发挥作用,就要基于两个假设:

o 读写的不对称性,读的次数远远大于写的次数。像数据库就是这样,决大部分时间是在查询,而修改的情况相对少得多,所以数据库通常使用读写锁。

o 处于临界区的时间比较长。从上面的实现来看,读写锁实际上比正常加/解锁的次数反而要多,如果处于临界区的时间比较短,比如和修改引用计数差不多,使用读写锁,即使全部是读,它的效率也会低于正常锁。

本节示例请到这里下载。

分享到:
评论

相关推荐

    《DB2程序员成长攻略》-龚涛-源代码

    《DB2程序员成长攻略》是龚涛先生撰写的一本专为DB2数据库系统开发者量身定制的实战指南。这本书深入浅出地介绍了DB2数据库的基础知识、开发技巧以及最佳实践,旨在帮助程序员快速提升在DB2环境下的技能水平。源代码...

    《Visual C++程序员成长攻略》-戴博-源代码

    《Visual C++程序员成长攻略》是一本专门为有一定Visual C++基础的开发者编写的进阶教程,作者戴博通过丰富的实践经验和深入浅出的讲解,帮助读者提升在C++编程领域的专业技能。这本书不仅包含了理论知识,更注重...

    程序员成长学习要求

    ### 程序员成长学习要求 在程序员的成长过程中,学习是不断进步的关键。下面将根据给定的信息,详细介绍一名程序员在职业发展道路上应该掌握的知识点。 #### Java基础及核心库 1. **理解SkillMap**:SkillMap是指...

    lixianjing.examples:lixianjing.examples系统程序员成长计划的

    "lixianjing.examples" 是一个开源项目,专为系统程序员的成长设计。这个项目的源码库包含了一系列用于学习和实践的示例,旨在帮助系统程序员提升技能,了解并掌握系统编程的关键概念和技术。从"lixianjing.examples...

    java程序员的成长历程

    以下就是一篇关于“Java程序员的成长历程”的详细解读。 首先,Java初学者通常会从学习基础语法开始,包括变量、数据类型、控制结构(如if语句和循环)、类与对象的概念。理解这些基础知识是构建扎实编程技能的第一...

    程序员编程艺术1-37章集锦

    12. **并发与多线程**:并发模型、线程同步、死锁预防等,为多核处理器环境下的编程提供指导。 13. **数据库编程**:SQL语言基础,数据库设计原则,以及如何通过API与数据库进行交互。 14. **安全性**:编程中的...

    深入理解计算机系统--程序员必学课程

    标题《深入理解计算机系统--程序员必学课程》所指向的知识点聚焦于计算机系统基础理论和...这本书的出版在学术和业界都受到了广泛的好评,它为计算机科学的教育和研究提供了宝贵的资源,是程序员成长为专家的必读之书。

    .net牛人知道(.net程序员成长必知)

    根据提供的文件信息,我们可以整理出一系列重要的 .NET 程序员成长过程中必须掌握的关键知识点。下面将逐一解析这些知识点,并提供详细的解释。 ### 1. Windows 应用程序与 EXE 文件 - **Windows 应用程序环境**:...

    程序员求职面试宝典

    例如,可能会问到排序算法的时间复杂度、如何设计一个高并发系统、SQL查询优化策略等。通过深入理解和解答这些题目,可以提升自身的技术能力,更好地应对面试挑战。 2. **面试技巧**:除了技术知识,面试技巧同样...

    DB2程序员成长攻略

    DB2程序员成长攻略 在IT领域,数据库管理是不可或缺的一部分,而DB2作为IBM公司推出的一款强大、可靠的数据库管理系统,广泛应用于企业级应用。对于希望在DB2领域深入发展的程序员来说,了解并掌握DB2的核心技术和...

    6个Java程序员的年度总结-精

    标题中的“6个Java程序员的年度总结-精”意味着这是一份包含六个Java程序员在过去一年中关于编程工作、学习和成长的总结性文档。这些程序员可能是来自不同背景、经验水平和项目领域的专家,他们分享了他们的知识、...

    《内外兼修(程序员的成长之路)》

    《内外兼修(程序员的成长之路)》是一本专注于程序员个人成长和职业发展的书籍,它深入探讨了在IT行业中,特别是Java编程领域,如何通过技术提升和软技能培养来实现全面的自我发展。这本书旨在帮助程序员从新手到资深...

    java程序员成长之路.doc

    "java程序员成长之路" Java 程序员的成长之路是一个长期的过程,需要不断学习和实践。本文将从初识 Java 到成为一名熟练的 Java 开发者,整个过程中需要掌握的知识点和技能。 首先,需要掌握 Java 的基础知识,...

    刚毕业的java程序员的未来出路--职业规划篇

    首先,你需要评估自己的技能水平,确定是否需要进一步提升,例如深入学习Java核心技术,如多线程、并发编程、Spring框架等。此外,了解并熟悉当前市场对Java开发人员的需求也是必要的。 【技能提升】在技能提升方面...

    程序员面试宝典 程序员

    《程序员面试宝典》是一本全面涵盖程序员面试过程...通过阅读《程序员面试宝典》和《第三章 三种考试(电子)》,程序员可以系统地准备面试,提高自己的竞争力,并在求职过程中展现出扎实的专业知识和良好的综合素质。

    商店管理系统(JAVA)(初级程序员的小项目)

    商店管理系统是许多初级程序员在学习Java编程时常常会接触到的一个小型项目。这个系统的主要目标是模拟现实中的商店运营,帮助用户进行商品管理、销售记录、库存控制等操作。在这个项目中,开发者会学习到Java的核心...

    程序员的十层楼.txt

    ### 一、程序员成长的十个阶段 1. **初识编程(第1层)** - **理解**:这一层主要强调的是对编程语言的基本认知,如C++中的类与对象的概念。 - **知识点**: - C++基本语法:包括变量定义、数据类型、运算符等。...

    [网盘]java程序员由菜鸟到笨鸟.pdf

    ### Java程序员成长之路——从菜鸟到笨鸟 #### 一、引言 《Java程序员由菜鸟到笨鸟》是一本由曹胜欢编写的书籍,旨在帮助初学者掌握Java编程的基础知识,并逐步进阶至更高级的应用场景。本书不仅适合初学者作为...

Global site tag (gtag.js) - Google Analytics