linux 读写锁 pthread_rwlock

  74ac905cfa3740079f2f66a445a3d7c2.gif#pic_center


目录

前言

概念介绍

应用场景

接口说明

头文件

rwlock定义

初始化/销毁

两种初始化方式

rwlock资源进行销毁

常见错误

属性设置

属性初始化/销毁

共享属性

阻塞式加锁

非阻塞加锁

编程示例

结尾


前言

本专栏主要分享linux下并发编程相关知识,包括多进程,多线程,进程/线程间通信,并发同步控制,以及高并发下性能提升,请大家多多留言。


概念介绍

        与前面介绍的互斥量,信号量类似,用于多线程/进程间同步控制,但与它们的不同之处在于,读写锁可以区分读加锁和写加锁,也就是说一把锁有两种不同的加锁方式,那么对于两种加锁方式下的并发控制也是不同。

这个不同点,也就是读写锁的精妙的所在。

 

应用场景

读写锁,有两种加锁方式:

(1)加读锁,也就是共享锁,多个并发可以同步加此种锁,同时可以访问临界区。

(2)加写锁,也就是独占锁,只有一个并发可以成功的加写锁,此时其它并发既不能加写锁,也不能加读锁,这就是独占的意义。

如下图所示:

97cea7eb836b4b78ba257f0d2f7ac210.png

基于rwlock的这个特点,在大并发中,读取临界区任务数量远远大于写临界区数量时,对于读任务只加共享读锁即可,比互斥量/信号量的性能会远远超过。

比如在系统中的用户信息,在每个并发登陆时都会访问,但它们大多数是只读,这样就可以共享访问,只对于少数注册/修改加写锁,此时互斥访问即可。

接口说明

头文件

 #include <pthread.h>

rwlock定义

pthread_rwlock_t rwlock;

当然定义了还不能用,此时状态未知,必须初始化后才能用。

初始化/销毁

  • 两种初始化方式

一种调用初始化接口,可以对rwlock的属性进行自定义设置,如果attr=NULL时,也会采用默认行为初始化;

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,

           const pthread_rwlockattr_t *restrict attr);

另一种采用静态初始化,此时采用的都是默认属性

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

默认初始化成功返回0,错误时查看errno,成功后状态为未加锁。

  • rwlock资源进行销毁

当然销毁的只是变量对应的资源,变量还可以再初始化;

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

  • 常见错误

几种未定义的行为,尽量避免踩坑:

(1)对还在加锁状态的rwlock进行销毁,行为没有定义,未知;

(2)对未初始化的rwlock进行销毁;

(3)多次初始化rwlock,可能会引起未知行为;

属性设置

  • 属性初始化/销毁

头文件为

#include <pthread.h>

定义rwlock属性变量

pthread_rwlockattr_t rwlock_attr;

初始化属性变量

int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);

销毁属性变量资源

int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);

  • 共享属性

头文件为

#include <pthread.h>

获取和设置属性接口

int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,

    int *pshared);

int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr,

    int pshared);

默认初始化时,共享属性为PTHREAD_PROCESS_PRIVATE,也就是只能在单个进程间的多线程间使用。

如果要在多个进程间的线程间使用,就需要将属性设置为PTHREAD_PROCESS_SHARED,也就是能访问rwlock变量内存的线程都可以使用,进行并发控制。

 

阻塞式加锁

加读锁,如果其它任务已经加了写锁,此时会阻塞等待

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

加写锁,如果其它任务已经加了读/写锁,此时会阻塞等待

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

释放锁,不论是读锁还是写锁,都调用统一释放接口

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

非阻塞加锁

尝试加读锁,成功则返回0,如果其它任务已经加了写锁,此时会返回失败,不会阻塞

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

尝试加写锁,成功则返回0,如果其它任务已经加了写/读锁,此时会返回失败,不会阻塞

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

错误码有:

[EBUSY] 获取锁失败

[EDEADLK] 当前任务已经获得了锁

编程示例

[senllang@localhost ex04_process]$ make
mkdir -p ./build
gcc  -I./  -I./build -DTEST_PRO -lpthread -g -c ipc_shmem.c
gcc  -I./  -I./build -DTEST_PRO -lpthread -g -c ipc_rwlock.c
gcc  -I./  -I./build -DTEST_PRO -lpthread -g -c main.c
gcc  -I./  -I./build -DTEST_PRO -lpthread -g -c ipc_mutex.c
gcc  -I./  -I./build -DTEST_PRO -lpthread -g -c process.c
gcc  -I./  -I./build -DTEST_PRO -lpthread -g -c ipc_shmem.c
gcc  -I./  -I./build -DTEST_PRO -lpthread -g *.o -o hatch-0-01
[senllang@localhost ex04_process]$ ./hatch-0-01 3 1

启动3个进程,定义1个rwlock,其中第一个进程是写锁处理,后面进程是读锁处理;

代码工程hatchCode

代码位于gitcode,请大家关注,后面会持续更新到此仓库。


结尾

作者邮箱:[email protected]
如有错误或者疏漏欢迎指出,互相学习。另外有什么想要了解的内容,也可以给我发邮件,互相谈讨,定知无不言。

注:未经同意,不得转载!

猜你喜欢

转载自blog.csdn.net/senllang/article/details/130784528