浅谈对读写锁的理解

浅谈对读写锁的理解

概念理解

读写锁,顾名思义,一个锁,分为两种形态,读状态和写状态,读写锁是专门为大多数读状态情况而设计的。这种情况下,读写锁可以提供比其他锁(比如互斥锁,自旋锁等)更大的扩张性,因为读写锁允许同一时刻多个读任务同时持有锁。增加读任务的并发性。

特征:写锁优先级高,写独占,读共享
1.写模式加锁时,解锁前,所有对该线程加锁的线程都会被阻塞。
2.读模式加锁时,如果线程是读加锁则成功,如果线程是写加锁会阻塞。
3.读锁、写锁并行阻塞时,写锁优先级高,即解锁后优先执行写锁操作。

具体api实现

posix api实现

pthread_rwlock_t类型 用于定义一个读写锁变量
int pthread_rwolck_init(pthread_rwlock_t*restrict rwlock,const pthread_rwlockattr_t*restrict attr);  
int pthread_rwlock_destroy(pthread_rwlock_t * 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);   
int pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock);
int pthread_rwlock_trywrock(pthread_rwlock_t * rwlock); 

dpdk api实现

typedef struct {
	volatile int32_t cnt; /**< -1 when W lock held, > 0 when R locks held. */
} rte_rwlock_t;
static inline void rte_rwlock_init(rte_rwlock_t *rwl)
static inline void rte_rwlock_read_lock(rte_rwlock_t *rwl)
static inline void rte_rwlock_read_unlock(rte_rwlock_t *rwl)
static inline void rte_rwlock_write_lock(rte_rwlock_t *rwl)
static inline void rte_rwlock_write_unlock(rte_rwlock_t *rwl)

dpdk在实现读写锁的时候,使用了原子锁机制
读锁加锁的时候,判断cnt是否小于0,如果是,表示当前处于写加锁状态,则需要把自己pause,否则直接使用原子操作cmpset把cnt+1.

static inline void
rte_rwlock_read_lock(rte_rwlock_t *rwl)
{
	int32_t x;
	int success = 0;

	while (success == 0) {
		x = rwl->cnt;
		/* write lock is held */
		if (x < 0) {
			rte_pause();
			continue;
		}
		success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
					      (uint32_t)x, (uint32_t)(x + 1));
	}
}

写锁的实现,判断当前cnt是否为0,为0表示没有读锁处于加锁状态,则把cnt使用原子操作cmpset设置为-1,
如果cnt>0,则把自己pause,等待读锁解锁。

static inline void
rte_rwlock_write_lock(rte_rwlock_t *rwl)
{
	int32_t x;
	int success = 0;

	while (success == 0) {
		x = rwl->cnt;
		/* a lock is held */
		if (x != 0) {
			rte_pause();
			continue;
		}
		success = rte_atomic32_cmpset((volatile uint32_t *)&rwl->cnt,
					      0, (uint32_t)-1);
	}
}

读写自旋锁主要用于比较短小的代码片段,线程等待期间不应该进入睡眠状态,因为睡眠/唤醒操作相当耗时,大大延长了获得锁的等待时间,所以我们要求忙等待。 申请锁的线程必须不断地查询是否发生退出等待的事件,不能进入睡眠状态。这个要求只是描述线程执行锁申请操作未成功时的行为,并不涉及锁自身的正确性。

本人从dpdk移植了锁实现到自己的github里面 https://github.com/air5005/usg/tree/master/libs/liblock 有兴趣的可以参考

linux kernel api实现

猜你喜欢

转载自blog.csdn.net/yaochuh/article/details/88083559