首页 > 代码库 > Linux环境编程之同步(三):读写锁

Linux环境编程之同步(三):读写锁

概述

互斥锁把试图进入我们称之为临界区的所有其他线程都阻塞住。该临界区通常涉及对由这些线程共享一个或多个数据的访问或更新。读写锁在获取读写锁用于读某个数据和获取读写锁用于写直接作区别。读写锁的分配规则如下:

1、只要没有线程持有某个给定的读写锁用于写,那么任意数目的线程可以持有该读写锁用于读。

2、仅当没有线程持有某个给定的读写锁用于读或用于写时,才能分配该读写锁用于写。

即只要没有线程在修改某个给定的数据,那么任意数目的线程都可以拥有该数据的读访问权。仅当没有其他线程在读或修改某个给定的数据时,当前线程才可以修改它。

这种对于某个给定资源的共享访问也称为共享-独占上锁,因为获取一个读写锁用于读称为共享锁,获取一个读写锁用于写称为独占锁

获取与释放读写锁

读写锁的数据类型为pthread_rwlock_t。如果这个类型的某个变量是静态分配的,则可通过给它赋常值PTHREAD_RWLOCK_INITIALIZER来初始化它。

pthread_rwlock_rdlock获取一个读出锁,如果对应的读写锁已由某个写入者持有,那就阻塞调用线程。pthread_rwlock_wrlock获取一个写入锁,如果对应的读写锁已由另一个写入者持有,或者已由一个或多个读出者持有,那就阻塞调用线程。pthread_rwlock_unlock释放一个读出锁或写入锁。

#include <pthread.h>
int	pthread_rwlock_rdlock(pthread_rwlock_t *rwptr);
int	pthread_rwlock_wrlock(pthread_rwlock_t *rwptr);
int	pthread_rwlock_unlock(pthread_rwlock_t *rwptr);    //成功返回0,出错返回为正的EXXX值。
下面两个函数尝试获取一个读出锁或写入锁,但如果该锁不能马上取得,那就返回一个EBUSY错误,而不是调用线程投入睡眠。

#include <pthread.h>
int	pthread_rwlock_tryrdlock(pthread_rwlock_t *rwptr);
int	pthread_rwlock_trywrlock(pthread_rwlock_t *rwptr); //成功返回0,出错返回正值
读写锁属性
给静态分配的读写锁赋值PTHREAD_RWLOCK_INITIALIZER来初始化它。读写锁变量也可通过调用pthread_rwlock_init来动态地初始化。当当一个线程不再需要某个读写锁时,可调用pthread_rwlock_destroy摧毁它。

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwptr, const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwptr);							//成功为0,出错为正值
初始化某个读写锁时,如果attr是空指针,就使用默认属性。要赋予它非默认的属性,需要使用如下两个函数:

#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t *rwptr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwptr);							//成功为0,出错为正值
数据类型为pthread_rwlockattr_t的某个属性对象一旦初始化,就通过调用不同的函数来启用或禁止特定属性。当前定义了的唯一属性是PTHREAD_PROCESS_SHARED,它指定相应的读写锁将不同进程间共享,而不仅仅是在单个进程内的不同线程间共享。以下两个函数分别获取和设置这个属性。

#include <pthread.h>
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *valptr);
int pthread_rwlockattr_setpshared(const pthread_rwlockattr_t *attr, int value);  //成功返回0,出错返回正值

读写锁的实现可参考《UNP2》P142