Linux线程同步之读写锁(rwlock)

Linux线程同步(3): 读写锁(rwlock)     在线程同步系列的第一篇文章里已经说过, 读写锁是因为有3种状态, 所以可以有更高的并行性.1. 特性:    一次只有一个线程可以占有写模式的读写锁, 但是可以有多个线程同时占有读模式的读写锁. 正是因为这个特性, 当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞. 当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的 阅读详情

读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步,

和互斥量不同的是:互斥量会把试图进入已保护的临界区的线程都阻塞;然而读写锁会视当前进入临界区的线程和请求进入临界区的线程的属性来判断是否允许线程进入。

相对互斥量只有加锁和不加锁两种状态,读写锁有三种状态:读模式下的加锁,写模式下的加锁,不加锁。

读写锁的使用规则:

  • 只要没有写模式下的加锁,任意线程都可以进行读模式下的加锁;
  • 只有读写锁处于不加锁状态时,才能进行写模式下的加锁;

读写锁也称为共享-独占(shared-exclusive)锁,当读写锁以读模式加锁时,它是以共享模式锁住,当以写模式加锁时,它是以独占模式锁住。读写锁非常适合读数据的频率远大于写数据的频率从的应用中。这样可以在任何时刻运行多个读线程并发的执行,给程序带来了更高的并发度。

需要提到的是:读写锁到目前为止仍然不是属于POSIX标准,本文讨论的读写锁函数都是有Open Group定义的的。例如下面是在我机器上,编译器是gcc version 4.4.6,关于读写锁的定义是包含在预处理命令中的:

#if defined __USE_UNIX98 || defined __USE_XOPEN2K

... 读写锁相关函数声明...

#endif
1读写锁的初始化和销毁
/* Initialize read-write lock  */
 int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
                                __const pthread_rwlockattr_t *__restrict __attr);

/* Destroy read-write lock */
extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);

                                               返回值:成功返回0,否则返回错误代码

上面两个函数分别由于读写锁的初始化和销毁。和互斥量,条件变量一样,如果读写锁是静态分配的,可以通过常量进行初始化,如下:

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

也可以通过pthread_rwlock_init()进行初始化。对于动态分配的读写锁由于不能直接赋值进行初始化,只能通过这种方式进行初始化。pthread_rwlock_init()第二个参数是读写锁的属性,如果采用默认属性,可以传入空指针NULL。

那么当不在需要使用时及释放(自动或者手动)读写锁占用的内存之前,需要调用pthread_rwlock_destroy()进行销毁读写锁占用的资源。

2读写锁的属性设置

/* 初始化读写锁属性对象 */
int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr);

/* 销毁读写锁属性对象 */
int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr);

/* 获取读写锁属性对象在进程间共享与否的标识*/
int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * __restrict __attr,
                                          int *__restrict __pshared);

/* 设置读写锁属性对象,标识在进程间共享与否  */
int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, int __pshared);

                                                    返回值:成功返回0,否则返回错误代码
这个属性设置和互斥量的基本一样,具体可以参考互斥量的设 置互斥量的属性设置

3读写锁的使用

/* 读模式下加锁  */
int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);

/* 非阻塞的读模式下加锁  */
int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);

# ifdef __USE_XOPEN2K
/*  限时等待的读模式加锁 */
int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
                                       __const struct timespec *__restrict __abstime);
# endif

/* 写模式下加锁  */
int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);

/* 非阻塞的写模式下加锁 */
int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);

# ifdef __USE_XOPEN2K
/* 限时等待的写模式加锁 */
int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
                                       __const struct timespec *__restrict __abstime);
# endif

/* 解锁 */
int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);

                                                   返回值:成功返回0,否则返回错误代码

(1)pthread_rwlock_rdlock()系列函数

pthread_rwlock_rdlock()用于以读模式即共享模式获取读写锁,如果读写锁已经被某个线程以写模式占用,那么调用线程就被阻塞。在实现读写锁的时候可以对共享模式下锁的数量进行限制(目前不知如何限制)。

pthread_rwlock_tryrdlock()和pthread_rwlock_rdlock()的唯一区别就是,在无法获取读写锁的时候,调用线程不会阻塞,会立即返回,并返回错误代码EBUSY。

pthread_rwlock_timedrdlock()是限时等待读模式加锁,时间参数struct timespec * __restrict __abstime也是绝对时间,和条件变量的pthread_cond_timedwait()使用基本一致,具体可以参考pthread_cond_timedwait() 3条件变量的使用

(2)pthread_rwlock_wrlock()系列函数

pthread_rwlock_wrlock()用于写模式即独占模式获取读写锁,如果读写锁已经被其他线程占用,不论是以共享模式还是独占模式占用,调用线程都会进入阻塞状态。

pthread_rwlock_trywrlock()在无法获取读写锁的时候,调用线程不会进入睡眠,会立即返回,并返回错误代码EBUSY。

pthread_rwlock_timedwrlock()是限时等待写模式加锁,也和条件变量的pthread_cond_timedwait()使用基本一致,具体可以参考pthread_cond_timedwait()3条件变量的使用。

(3)pthread_rwlock_unlock()

无论以共享模式还是独占模式获得的读写锁,都可以通过调用pthread_rwlock_unlock()函数进行释放该读写锁。

下面是测试代码:

#include <iostream>
#include <cstdlib>

#include <unistd.h>
#include <pthread.h>

using namespace std;

struct{
    pthread_rwlock_t rwlock;
    int product;
}sharedData = {PTHREAD_RWLOCK_INITIALIZER, 0};

void * produce(void *ptr)
{
    for (int i = 0; i < 5; ++i)
    {
        pthread_rwlock_wrlock(&sharedData.rwlock);
        sharedData.product = i;
        pthread_rwlock_unlock(&sharedData.rwlock);

        sleep(1);
    }
}

void * consume1(void *ptr)
{
    for (int i = 0; i < 5;)
    {
        pthread_rwlock_rdlock(&sharedData.rwlock);
        cout<<"consume1:"<<sharedData.product<<endl;
        pthread_rwlock_unlock(&sharedData.rwlock);

        ++i;
        sleep(1);
    }
}

void * consume2(void *ptr)
{
    for (int i = 0; i < 5;)
    {
        pthread_rwlock_rdlock(&sharedData.rwlock);
        cout<<"consume2:"<<sharedData.product<<endl;
        pthread_rwlock_unlock(&sharedData.rwlock);

        ++i;
        sleep(1);
    }
}

int main()
{
    pthread_t tid1, tid2, tid3;

    pthread_create(&tid1, NULL, produce, NULL);
    pthread_create(&tid2, NULL, consume1, NULL);
    pthread_create(&tid3, NULL, consume2, NULL);

    void *retVal;

    pthread_join(tid1, &retVal);
    pthread_join(tid2, &retVal);
    pthread_join(tid3, &retVal);

    return 0;
}

测试结果如下:

consume1:0
consume2:0
consume2:0
consume1:1
consume2:1
consume1:2
consume2:2
consume1:3
consume2:3
consume1:4

如果把consume1的解锁注释掉,如下:

void * consume1(void *ptr)
{
    for (int i = 0; i < 5;)
    {
        pthread_rwlock_rdlock(&sharedData.rwlock);
        cout<<"consume1:"<<sharedData.product<<endl;
        //pthread_rwlock_unlock(&sharedData.rwlock);

        ++i;
        sleep(1);
    }
}

程序的执行结果如下:

consume1:0
consume2:0
consume2:0
consume1:0
consume2:0
consume1:0
consume2:0
consume1:0
consume2:0
consume1:0

从执行结果可以看出Linux 2.6.18提供的读写锁函数是优先考虑等待读模式占用锁的线程,这种实现的一个很大缺陷就是出现写入线程饿死的情况。


Jun 26, 2013 AM 00:08 @Library

stc8g1k08硬件iic读取aht20温湿度及0.91寸oled显示 使用stc8g1k08读取aht20温湿度及0.91寸oled显示。 阅读详情

相关推荐

PyQtWebEngine安装避坑指南:快速解决ModuleNotFoundError

本文详细解析了PyQt5开发中常见的ModuleNotFoundError: No module named 'PyQt5.QtWebEngineWidgets'错误。核心原因是PyQt5 5.11版本后,网页引擎组件被独立为PyQtWebEngine包。文章对比了退回旧版本、独立安装及使用Conda等多种解决方案,并提供了针对Windows、macOS和Linux不同平台的实战安装指南与验证方法,帮助开发者快速解决依赖问题。

weixin_29056101的博客 427

__USE_XOPEN2K宏定义

__USE_XOPEN2K是一个宏定义,用于启用一组支持 X/Open Portability Guide Issue 4(XPG4)的特性,这些特性包括很多常用的标准 POSIX 函数,比如strptime()、gettimeofday()、timer_create()等。

weixin_52018852的博客 1020

【人工智能】人工智能基础概念、流派、发展史

人工智能初衷就是让计算机能够像人类一样具有自我思考、自我学习、自我决策的能力。依据百度百科上对人工智能定义:人工智能是研究、开发用于模拟、扩展和延伸人的智能的理论、方法、技术及应用系统的一门新的技术学科。人工智能是研究使计算机来模拟人的某些思维过程和智能行为的学科,主要包括计算机实现智能的原理、制造类似于人脑智能的计算机,使计算机能实现更高层次的应用。

WEL测试 1882

【Linux】vscode 对 pthread_rwlock_t 等报错 解决方法

在Linux环境下使用 VScode 编写C代码,在进行关于进程、现程开发的时候,一些系统调用或者定义(比如像等) 编辑器都无法解析出来,经常会出现无法跳转函数定义、飘红等,除了没有 include 相关的头文件之外,很可能是没有进行宏定义导致的 VScode 解析器无法识别。

weixin_46512400的博客 1914

计算机视觉:暗通道去雾算法的原理及python实现

在绝大多数非天空的局部区域中,某些像素总会至少有一个颜色通道的值很低。对于一幅图像J(x),其暗通道的数学定义表示如下:其中,Ω(x)表示以x为中心的局部区域,上标c表示RGB三个通道。该公式的意义用代码表达也很简单,首先求出每个像素RGB分量中的最小值,存入一副和原始图像大小相同的灰度图中,然后再对这幅灰度图进行最小值滤波,滤波的半径由窗口大小决定。

weixin_51998427的博客 1万+

引入 CloudWeGo 后飞书管理后台平台化改造的演进史

飞书管理后台是飞书套件专为企业管理员提供的信息管理平台,它通过引入 Kitex 泛化调用对飞书管理后台进行平台化改造,成为了企业统一数字化管理平台。本文将从三个方面为大家讲解 Kitex 泛化调用在飞书管理后台平台化改造过程中的落地实践。...

weixin_44186218的博客 1762

linux-读写锁(rwlock)

动态初始化是在堆中申请空间,需要释放,而静态初始化是在静态存储区中创建,不。在 linux 中,通过 pthread_rwlock_t 结构来表示一个读写锁。1.如果有其它线程读数据,则允许其它线程执行读操作,但不允许写操作;3 如果某线程申请了读锁,其它线程可以再申请读锁,但不能申请写锁;4.如果某线程申请了写锁,其它线程不能申请读锁,也不能申请写锁。读写锁与互斥量类似,不过读写锁允许更改的并行性,释放读写锁(pthread_rwlock_destroy)读写锁的属性,为 NULL 表示默认属性。

jiu_yue_ya的博客 799

CST中PEC结构涂覆吸波材料的RCS仿真与优化

本文详细介绍了在CST Studio Suite中对PEC结构涂覆吸波材料进行RCS仿真的完整流程与优化策略。通过精确的材料参数设置、涂层厚度优化和仿真技巧,有效降低目标的雷达散射截面,提升隐身性能。文章结合实战案例,为工程师提供了一套高效的RCS仿真与优化解决方案。

c2d3e4f的博客 693

Linux——关于互斥锁为什么不初始化也能使用的原因

为什么互斥锁不初始化也能用

qq_52479948的博客 1274

别再为GEE注册发愁了!用谷歌Cloud Project,5分钟搞定谷歌地球引擎账户(保姆级图文)

本文提供2024最新版谷歌地球引擎(GEE)账户注册的保姆级教程,通过谷歌Cloud Project快速完成注册,5分钟极速通关。详细解析注册前的准备、分步图解流程、常见误区及解决方案,帮助用户避开90%的注册陷阱,直达GEE核心功能区。

weixin_42557830的博客 200

五、e2studio VS STM32CubeIDE之汉化

介绍stm32cubeide汉化方案和汉化包e2studio自带汉化包,在安装过程中可选择安装e2studio STM32CubeIDE切换中英文。

cl234583745的博客 1769

【Linux系统编程】多线程编程:线程同步机制-rwlock(读写锁)

读写锁(Readers-Writer Lock)是一种多线程同步机制,用于控制对共享资源的访问。与传统的互斥锁(Mutex)不同,它允许多个读操作同时进行,但写操作必须独占访问。这可能比普通的互斥锁更高效,特别是在读多写少的场景下。使用读写锁的场景通常包括共享数据结构如缓存、数据库等。比如,一个数据库系统中,如果读请求(如查询)远大于写请求(如更新),使用读写锁可以让多个查询线程并行访问数据,从而提升系统的响应速度。

Stark的博客 1143

银河麒麟桌面系统批量交付:封装自动化ISO镜像,百台装机效率提升10倍

麒麟桌面系统自动化ISO镜像定制摘要 本文详细介绍麒麟桌面版ISO安装镜像的定制方法,通过修改系统文件实现自动化安装部署。主要内容包括:1) 挂载原版ISO并提取文件;2) 使用unsquashfs解压系统文件进行定制化修改,包括添加系统标记配置;3) 配置ky-installer.cfg自动应答文件,设置安装参数如用户名、密码、分区方案等;4) 修改grub引导配置启用自动安装模式。该流程支持磁盘加密、自定义分区、自动登录等功能,生成的定制镜像可满足批量部署需求,显著提升系统安装效率。

信创运维工程师 · 银河麒麟 & 容器实战 | 金融生产环境迁移·等保加固 | 142篇原创·17万+阅读 1508

Linux线程同步读写锁 rwlock

Linux线程同步读写锁 rwlock 转自:http://yaronspace.cn/blog/archives/1135  读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁。 1. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞; 2. 当读写锁在读加锁状态时,所有试图以读模式对它进行加锁

qq_37803909的博客 155

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

linux线程同步种类,Linux线程同步之读写锁(rwlock)

读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步,和互斥量不同的是:互斥量会把试图进入已保护的临界区的线程都阻塞;然而读写锁会视当前进入临界区的线程和请求进入临界区的线程的属性来判断是否允许线程进入。相对互斥量只有加锁和不加锁两种状态,读写锁有三种状态:...

weixin_42668301的博客 386

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

linux线程同步方式5——读写锁(rwlock)

读写锁(rwlock)读写锁1、背景和定义1. 背景:读者和写者问题2. 定义3. 读写锁三种状态4. 读写锁特性2、初始化3、请求读锁(阻塞)4、请求读锁(非阻塞)5、请求写锁(阻塞)6、请求写锁(非阻塞)7、解锁8、销毁互斥锁、读写锁、自旋锁区别应用举例参考 读写锁 #include <pthread.h> 1、背景和定义 1. 背景:读者和写者问题 有一群写者和一群读者,写者在写同一本书,读者也在读这本书,多个读者可以同时读这本书,但是,只能有一个写者在写书。特征: (1)任意多的读进

JMW1407的博客 3914

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

linux系统编程:线程同步-读写锁(rwlock)

线程同步-读写锁(rwlock)读写锁读写锁是互斥量的细化:显然,只有对全局资然进行写入操作时,才需要同步;在对全局资然进行读取操作时,是不需要锁的。pthread_rwlock_t pthread_rwlock_init pthread_rwlock_destroy pthread_rwlock_rdlock pthread_rwlock_wrlock pthread_rwlock_tryrdl

CCPP Blog 2383

Linux线程同步 读写锁 rwlock

读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁。 1. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞; 2. 当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行枷锁的线程将阻塞; 3. 当读写锁在读模式锁状态时,如果有另外线程试图以写模式加锁,读写锁...

jie310600的博客 206
上一篇: Linux线程同步之条件变量
下一篇: Linux进程同步之记录锁(fcntl)
walker沃克
博客等级 码龄16年 208粉丝 60原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值