Fork me on GitHub

如何设计一个读写锁

  说起锁,大家都不会感到陌生,在多线程编程的时候,为了保证线程安全,需要给特定的代码段进行加锁执行完毕后再进行解锁。

  不过,有一个场景比较特殊:假设有一个文件,我们肯定不希望读操作和写操作同时进行,但是除了这一点,在读取的时候,其实我们没有必要对其他的读取操作进行加锁,这样显得更为合理,那么如何去实现这样一个锁呢?(写入的时候加锁,阻止读取操作和其他的写入操作。读取的时候也加锁,阻止写入操作,但是不阻止其他的读取操作)

  既然需求已经明确了,那我们就来梳理一下思路。

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
43
44
45
46
47
48
49
50
// 1 一个资源同时可以有多个读写,但是只能有一个写锁

// 2 用flag代表锁的状态,
#define un_lock 0
#define r_lock 1 //上一把读锁加一个r_lock
#define w_lock -1

// 3. 伪代码
// 3.1 LOCK_R

pthread_lock(resource.mutex)

while(resource.flag < 0 ) // 说明当前资源为写锁
pthread_cond_wait(resource.cond, resource.mutex)

// 说明当前资源为无锁或者读锁,再加一把读锁
resource.flag+=r_lock
pthread_unlock(resource.mutex)

// 3.2 UNLOCK_R

pthread_lock(resource.mutex)

// 减去一把读锁
resource.flag-=r_lock
if (resource.flag == 0) // 说明当前资源为写锁
pthread_cond_broadcast(resource.cond) // 这个操作激活所有上写锁的线程

pthread_unlock(resource.mutex)

// 3.3 LOCK_W

pthread_lock(resource.mutex)

while(resource.flag != 0 ) // 说明当前资源为写锁或者读锁
pthread_cond_wait(resource.cond, resource.mutex)

// 说明当前资源为无锁
resource.flag=w_lock
pthread_unlock(resource.mutex)

// 3.4 UNLOCK_W

pthread_lock(resource.mutex)

// 减去写锁
resource.flag=w_lock
pthread_cond_broadcast(resource.cond) // 这个操作激活所有上写锁和读锁的线程

pthread_unlock(resource.mutex)

  然后还有一些情况需要考虑:当前有未执行的读操作,也有写操作等待执行,那么我们如何来处理读写优先级的问题呢,这些都是在后期结合需求考虑去优化的问题。

------------- 本文结束感谢您的阅读 -------------