多线程同步中最简单的锁是互斥体(mutex),我们把线程比喻为人,而共享资源是一个公共洗手间,一次只能进一个人,A抢先进去把门锁住,其他人只能在外面等待,等A好了开门出来,其他人才有机会进入洗手间。这个过程抽象为获得锁和释放锁两个动作,一个线程获得锁后开始访问共享资源,其他线程若想访问这个共享资源,要先获得锁,可是此时锁已经被其他线程获得,那么它只能等待,直到那个线程释放了锁。
但是互斥体在某些情况下并不高效,比如某个共享数据,它被多个线程频繁地读取,但偶尔会被修改,假如没有发生写操作,那么多个线程同时读是安全的,只有在有写操作发生时,其他线程的读写才需要同步。这种情况如果使用互斥体,会使读操作失去并发能力。
读写锁就是用于这种场景,它可以提高读操作的并发,读写锁把锁分成读锁和写锁:
- 一个线程想获得写锁:如果此时有其他线程已经获得了读锁或写锁,该线程会等待。
- 一个线程想获得读锁:
- 如果此时有其他线程已经获得写锁,该线程会等待。
- 否则如果其他线程只获得了读锁,该线程也能顺利获得读锁。
简单言之,它所要实现的效果就是允许多个线程同时读数据,而写数据则必须保证没有其他线程在读写。
了解了读写锁的含义,可以自己实现一个,内部实现需要用到内存的原子操作,我们借用GCC的内建原子函数:
// 对ptr指向的内存值加上value,返回加之前的内存值
具体的API文档在这里:Atomic-Builtins
有了这些原子函数,读写的实现代码如下(取自skynet的实现):
// 读写锁结构
pthread提供了一套读写锁的API,接口也非常简单:
// 初始化读写锁
更多读写锁的API,请参看文档