ceph中的RWLock

Linux中的读写锁

linux中的pthread_rwlock_t即为linux中的读写锁,读写锁的相关API介绍如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
初始化读写锁                            pthread_rwlock_init 

读取读写锁中的锁 pthread_rwlock_rdlock

读取非阻塞读写锁中的锁 pthread_rwlock_tryrdlock

写入读写锁中的锁 pthread_rwlock_wrlock

写入非阻塞读写锁中的锁 pthread_rwlock_trywrlock

解除锁定读写锁 pthread_rwlock_unlock

销毁读写锁 pthread_rwlock_destroy

初始化读写锁

使用 pthread_rwlock_init(&rwlock,NULL) 可以通过attr所引用的属性初始化rwlock所引用的读写锁。

pthread_rwlock_init 语法

1
2
3
#include <pthread.h>    
int pthread_rwlock_init(pthread_rwlock_t *rwlock,const pthread_rwlockattr_t *attr);
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

如果 attr 为 NULL,则使用缺省的读写锁属性,其作用与传递缺省读写锁属性对象的地址相同。初始化读写锁之后,该锁可以使用任意次数,而无需重新初始化。成功初始化之后,读写锁的状态会变为已初始化和未锁定。如果调用pthread_rwlock_init() 来指定已初始化的读写锁,则结果是不确定的。如果读写锁在使用之前未初始化,则结果是不确定的。

如果缺省的读写锁属性适用,则 PTHREAD_RWLOCK_INITIALIZER 宏可初始化以静态方式分配的读写锁,其作用与通过调用pthread_rwlock_init() 并将参数attr 指定为 NULL 进行动态初始化等效,区别在于不会执行错误检查。

pthread_rwlock_init 返回值

如果成功,pthread_rwlock_init() 会返回零。否则,将返回用于指明错误的错误号。

如果 pthread_rwlock_init() 失败,将不会初始化rwlock,并且rwlock 的内容是不确定的。

获取读写锁中的读锁

pthread_rwlock_rdlock 语法

pthread_rwlock_rdlock(&rwlock)可用来向rwlock所引用的读写锁应用读锁。

1
2
#include <pthread.h>    
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock );

如果写入器未持有读锁,并且没有任何写入器基于该锁阻塞,则调用线程会获取读锁。如果写入器未持有读锁,但有多个写入器正在等待该锁时,调用线程是否能获取该锁是不确定的。如果某个写入器持有读锁,则调用线程无法获取该锁。如果调用线程未获取读锁,则它将阻塞。调用线程必须获取该锁之后,才能从pthread_rwlock_rdlock() 返回。如果在进行调用时,调用线程持有rwlock 中的写锁,则结果是不确定的。

为避免写入器资源匮乏,允许在多个实现中使写入器的优先级高于读取器。

一个线程可以在 rwlock 中持有多个并发的读锁,该线程可以成功调用pthread_rwlock_rdlock()n 次。该线程必须调用pthread_rwlock_unlock()n 次才能执行匹配的解除锁定操作。

如果针对未初始化的读写锁调用 pthread_rwlock_rdlock(),则结果是不确定的。

线程信号处理程序可以处理传送给等待读写锁的线程的信号。从信号处理程序返回后,线程将继续等待读写锁以执行读取,就好像线程未中断一样。

pthread_rwlock_rdlock 返回值

如果成功,pthread_rwlock_rdlock() 会返回零。否则,将返回用于指明错误的错误号。

写入读写锁中的锁

pthread_rwlock_wrlock(&rwlock) 可用来向rwlock所引用的读写锁应用写锁。

pthread_rwlock_wrlock 语法

1
2
#include <pthread.h>    
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );

如果没有其他读取器线程或写入器线程持有读写锁rwlock,则调用线程将获取写锁。否则,调用线程将阻塞。调用线程必须获取该锁之后,才能从pthread_rwlock_wrlock()调用返回。如果在进行调用时,调用线程持有读写锁(读锁或写锁),则结果是不确定的。

为避免写入器资源匮乏,允许在多个实现中使写入器的优先级高于读取器。
如果针对未初始化的读写锁调用 pthread_rwlock_wrlock(),则结果是不确定的。
线程信号处理程序可以处理传送给等待读写锁以执行写入的线程的信号。从信号处理程序返回后,线程将继续等待读写锁以执行写入,就好像线程未中断一样。

pthread_rwlock_wrlock 返回值

如果获取了用于在 rwlock 所引用的读写锁对象中执行写入的锁,则pthread_rwlock_rwlock() 将返回零。如果没有获取该锁,则返回用于指明错误的错误号。

解除锁定读写锁

pthread_rwlock_unlock(&rwlock) 可用来释放在rwlock引用的读写锁对象中持有的锁。

pthread_rwlock_unlock 语法

1
2
#include <pthread.h>    
int pthread_rwlock_unlock (pthread_rwlock_t *rwlock);

如果调用线程未持有读写锁rwlock,则结果是不确定的。

如果通过调用 pthread_rwlock_unlock() 来释放读写锁对象中的读锁,并且其他读锁当前由该锁对象持有,则该对象会保持读取锁定状态。如果pthread_rwlock_unlock() 释放了调用线程在该读写锁对象中的最后一个读锁,则调用线程不再是该对象的属主。如果pthread_rwlock_unlock() 释放了该读写锁对象的最后一个读锁,则该读写锁对象将处于无属主、解除锁定状态。

如果通过调用 pthread_rwlock_unlock() 释放了该读写锁对象的最后一个写锁,则该读写锁对象将处于无属主、解除锁定状态。
如果 pthread_rwlock_unlock() 解除锁定该读写锁对象,并且多个线程正在等待获取该对象以执行写入,则通过调度策略可确定获取该对象以执行写入的线程。如果多个线程正在等待获取读写锁对象以执行读取,则通过调度策略可确定等待线程获取该对象以执行写入的顺序。如果多个线程基于rwlock 中的读锁和写锁阻塞,则无法确定读取器和写入器谁先获得该锁。

如果针对未初始化的读写锁调用 pthread_rwlock_unlock(),则结果是不确定的。

pthread_rwlock_unlock 返回值

如果成功,pthread_rwlock_unlock() 会返回零。否则,将返回用于指明错误的错误号。

销毁读写锁

pthread_rwlock_destroy(&rwlock) 可用来销毁rwlock 引用的读写锁对象并释放该锁使用的任何资源。

pthread_rwlock_destroy 语法

1
2
3
#include <pthread.h>    
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

在再次调用 pthread_rwlock_init() 重新初始化该锁之前,使用该锁所产生的影响是不确定的。

pthread_rwlock_destroy 返回值

如果成功,pthread_rwlock_destroy() 会返回零。否则,将返回用于指明错误的错误号。

Ceph RWLock解析

ceph中的RWLock是基于linux的读写锁实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class RWLock {
主要数据成员:
pthread_rwlock_t L: pthread库中的读写锁
string name: 读写锁的名称
atomic nrlock, nwlock: 读锁和写锁的引用计数

主要成员函数:
RWLock():
读写锁的构造函数会根据输入的参数设置读写锁的属性,主要是防止长时间的读造成写的饿死情况.
is_locked():
is_wlocked():
is_rlocked():
判断锁的状态.
unlock():
读锁和写锁的解锁都基于它进行解锁操作
get_read():
put_read():
try_get_read():
读锁的lock, unlock和try_lock
get_write():
put_write():
try_get_write():
写锁的lock,unlock和try_lock
get(bool):
参数为true,写锁加锁,否则读锁加锁
}

读锁
class RLocker {
构造函数加锁,析构函数解锁,主要用于语句块中
}

写锁
class WLocker {
构造函数加锁,析构函数解锁,主要用于语句块中
}

Context
Context和RWLock基本相同,只不过多了一个写锁强占读锁的函数.
class Context {
void promote(): 读锁可以被写锁强占.
}