- 专栏内容:linux下并发编程
- 个人主页:我的主页
- 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.
目录
前言
概念介绍
应用场景
接口说明
头文件
rwlock定义
初始化/销毁
两种初始化方式
rwlock资源进行销毁
常见错误
属性设置
属性初始化/销毁
共享属性
阻塞式加锁
非阻塞加锁
编程示例
结尾
前言
本专栏主要分享linux下并发编程相关知识,包括多进程,多线程,进程/线程间通信,并发同步控制,以及高并发下性能提升,请大家多多留言。
概念介绍
与前面介绍的互斥量,信号量类似,用于多线程/进程间同步控制,但与它们的不同之处在于,读写锁可以区分读加锁和写加锁,也就是说一把锁有两种不同的加锁方式,那么对于两种加锁方式下的并发控制也是不同。
这个不同点,也就是读写锁的精妙的所在。
应用场景
读写锁,有两种加锁方式:
(1)加读锁,也就是共享锁,多个并发可以同步加此种锁,同时可以访问临界区。
(2)加写锁,也就是独占锁,只有一个并发可以成功的加写锁,此时其它并发既不能加写锁,也不能加读锁,这就是独占的意义。
如下图所示:
基于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,请大家关注,后面会持续更新到此仓库。
结尾
作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。另外有什么想要了解的内容,也可以给我发邮件,互相谈讨,定知无不言。
注:未经同意,不得转载!