概述

freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性。

线程读写锁在多线程服务中有重要的作用。对于读数据比写数据频繁的服务,用读写锁代替互斥锁可以提高效率。

由于APR库是跨平台的,而不同平台上的系统接口有区别,所以在APR库中就有一个适配层目录libs\apr\include\arch\,该目录下有不同系统的头文件定义,包括aix、beos、netware、os2、os390、unix、win32。

在编译源代码文件的过程中,根据当前系统自动选择不同的文件目录来适配。

下面我们对apr库的线程读写锁实现做一个介绍。

环境

centos:CentOS  release 7.0 (Final)或以上版本

freeswitch:v1.8.7

GCC:4.8.5

读写锁数据结构

apr库的线程读写锁源代码文件在libs/apr目录下,这里只列出了unix和win32的版本。

libs\apr\include\apr_thread_rwlock.h

libs\apr\include\arch\unix\apr_arch_thread_rwlock.h

libs\apr\locks\unix\thread_rwlock.c

libs\apr\include\arch\win32\apr_arch_thread_rwlock.h

libs\apr\locks\win32\thread_rwlock.c

读写锁结构体定义。

我们可以看出,在unix系统下直接使用了pthread线程库的读写锁实现。

libs\apr\include\arch\unix\apr_arch_thread_rwlock.h

struct apr_thread_rwlock_t {

apr_pool_t *pool;

pthread_rwlock_t rwlock;

};

在win32系统则是使用了临界区CRITICAL_SECTION、mutex和event协同实现。

libs\apr\include\arch\win32\apr_arch_thread_rwlock.h

struct apr_thread_rwlock_t {

apr_pool_t *pool;

HANDLE      write_mutex;

HANDLE      read_event;

LONG        readers;

CRITICAL_SECTION  read_section;

};

常用函数

查看源代码头文件libs\apr\include\apr_thread_rwlock.h。

apr_thread_rwlock_create           //创建并初始化1个线程读写锁

apr_thread_rwlock_rdlock           //获取1个共享读锁

apr_thread_rwlock_tryrdlock       //非阻塞获取1个共享读锁

apr_thread_rwlock_wrlock          //获取1个独占写锁

apr_thread_rwlock_trywrlock      //非阻塞获取1个独占写锁

apr_thread_rwlock_unlock          //解锁1个读写锁

apr_thread_rwlock_destroy         //销毁读写锁

从接口定义我们可以看出,加读锁和加写锁是分开的接口,而解锁是同一个接口。

接口的实现我们简单介绍一下。

在unix系统下,读写锁的接口中直接调用了pthread库中对应的读写锁接口。

比如apr_thread_rwlock_create中调用了pthread_rwlock_init,apr_thread_rwlock_rdlock中调用了pthread_rwlock_rdlock等等,这里就不再详细展开了,有兴趣的可以自己查看一下pthread_rwlock_t读写锁的定义和实现。

在win32系统下,读写锁的接口中使用了readers、read_event、write_mutex和read_section几个变量共同实现了读写锁的功能。

伪代码-读锁(读写锁, 超时时间)

进入临界区read_section

等待信号write_mutex,失败或超时则返回错误

计数器readers+1

重置事件read_event,失败则返回错误

释放write_mutex,失败则返回错误

离开临界区read_section

返回成功

伪代码-写锁(读写锁, 超时时间)

等待信号write_mutex,失败或超时则返回错误

等待信号read_event,失败或超时则释放write_mutex,并返回错误

返回成功

伪代码-解锁(读写锁)

释放write_mutex

计数器readers-1

设置事件read_event

返回

说实话。。。win32的代码我没看懂,有没有win开发的高手给讲解一下。

比如,为什么只有读锁中有临界区read_section的操作,为什么write_mutex只有释放操作,为什么写锁中没有等待readers为0。。。

总结

apr库的线程读写锁的实现介绍完了。

读写锁的适用场景是多线程下读多写少的业务流程,以实现独占写和共享读的逻辑。

在合适的场景中,读写锁比互斥锁有更高的并发能力和效率。

另外,还有强读者和强写者俩种不同的形式,读者可以自己深入研究一下。


空空如常

求真得真

freeswitch APR库线程读写锁的更多相关文章

  1. freeswitch APR库

    概述 freeswitch依赖库源代码基本都可以在libs目录下找到. 在freeswitch的官方手册中,可以找到freeswitch的依赖库表格,其中freeswitch的core核心代码依赖库主 ...

  2. freeswitch APR库哈希表

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. 哈希表在开发中应用的非常广泛,主要场景是对查询效率要求较高的逻辑,是典型的空间换时间的数据结构实现. 大多数 ...

  3. freeswitch APR-UTIL库线程池实现分析

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. APR库在之前的文章中已经介绍过了,APR-UTIL库是和APR并列的工具库,它们都是由APACHE开源出来 ...

  4. Java线程读写锁

    排他锁和共享锁: 读写锁:既是排他锁,又是共享锁.读锁,共享锁,写锁:排他锁 读和读是不互斥的 import java.util.HashMap; import java.util.Map; impo ...

  5. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

  6. Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock)

    Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在学习Java的之前,你可能已经听说过读 ...

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

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

  8. linux线程同步(3)-读写锁

    一.概述                                                    读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区, ...

  9. 第8章 用户模式下的线程同步(3)_Slim读写锁(SRWLock)

    8.5 Slim读/写锁(SRWLock)——轻量级的读写锁 (1)SRWLock锁的目的 ①允许读者线程同一时刻访问共享资源(因为不存在破坏数据的风险) ②写者线程应独占资源的访问权,任何其他线程( ...

随机推荐

  1. Python--基本数据类型(可变/不可变类型)

    目录 Python--基本数据类型 1.整型 int 2.浮点型 float 3.字符串 str 字符串格式 字符串嵌套 4.列表 list 列表元素的下标位置 索引和切片:字符串,列表常用 5.字典 ...

  2. python中jsonpath模块,解析多层嵌套的json数据

    1. jsonpath介绍用来解析多层嵌套的json数据;JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Python, ...

  3. 『学了就忘』Linux软件包管理 — 46、yum命令详细介绍

    目录 1.yum命令的查询操作 2.使用yum命令安装服务 3.使用yum命令升级服务 4.使用yum命令卸载服务 5.yum组管理命令 (1)查询可以安装的软件组 (2)查询软件组内包含的软件 (3 ...

  4. python实现直方图的应用

    目录: (一)调节图片对比度(均衡化) (1)全局直方图均衡化------equalizeHist (2)自适应的局部的直方图均衡化------createCLAHE (二)图片的相似度比较 (三)直 ...

  5. 使用json.net实现复杂对象转换为QueryString

    目标:生成复杂对象的QueryString,比如 new { Field1 = 1, Field2 = new { Field3 = "2", Field4 = new[] { n ...

  6. Go语言核心36讲(Go语言实战与应用九)--学习笔记

    31 | sync.WaitGroup和sync.Once 我们在前几次讲的互斥锁.条件变量和原子操作都是最基本重要的同步工具.在 Go 语言中,除了通道之外,它们也算是最为常用的并发安全工具了. 说 ...

  7. vue3 学习笔记 (五)——vue3 的 setup 如何实现响应式功能?

    setup 是用来写组合式 api ,内部的数据和方法需要通过 return 之后,模板才能使用.在之前 vue2 中,data 返回的数据,可以直接进行双向绑定使用,如果我们把 setup 中数据类 ...

  8. COS 音视频实践 | 多种姿势让你的视频“跑”起来

    导语 随着4G/5G时代的到来,短视频/直播行业开始流行,音视频逐渐成为信息传播中流量占比最大的部分.腾讯云对象存储(COS)作为可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务, ...

  9. 使用国内的镜像源搭建 kubernetes(k8s)集群

    1. 概述 老话说的好:努力学习,提高自己,让自己知道的比别人多,了解的别人多. 言归正传,之前我们聊了 Docker,随着业务的不断扩大,Docker 容器不断增多,物理机也不断增多,此时我们会发现 ...

  10. [POI2002][HAOI2007]反素数

    题意 反素数 想法 证明这样一个结论 对于一个可行的反素数\(p\) \(p = \sum_{i}^{k} p_{k} ^ {c_k}\) 当 \(p_i > p_j 有 c_i < c_ ...