读者写者模型(读写锁)
在编写多线程时,有可能会出现有些公共区域的数据修改的机会比较少,但是读的机会反而很多,也就是说写者少,读者多。那么在读的过程中往往伴随着查找的操作,耗时较长,如果给这种代码加锁的话,会导致效率的降低,因此读写锁就是针对多读少写的情况。
当前锁状态 | 读锁请求 | 写锁请求 |
---|---|---|
无锁 | 可以 | 可以 |
读锁 | 可以 | 阻塞 |
写锁 | 阻塞 | 阻塞 |
这里默认是读锁优先的,因为读者非常的多,但是这样也就会导致写锁的饥饿问题。
读者写者模型和生产者消费者模型的区别?
读者写者模型和生产者消费者模型最大的区别就是生产者生产数据之后,消费者就会将数据消费掉,其他消费者则无法享受该数据。而读者写者模型中写者进行数据的写入时,所有的读者都可以享受该数据,直到写者再次写入。
读者写者模型中的三重关系?
写者和写者的关系:互斥
读者和读者的关系:共享
读者和写者的关系:互斥和同步(当写者进行数据写入时,读者不可以进行数据的读取,当读者进行数据的读取时,写者不可以进行数据的写入,同时读者必须等待写者把数据写完才可以进行数据的写入)
既然读读不互斥,为何还要加读锁?
答: 如果只是读,是不需要加锁的,加锁本身就有性能上的损耗
如果读可以不是最新数据,也不需要加锁
如果读必须是最新数据,必须加读写锁
读写锁相较于互斥锁的优点仅仅是允许读读的并发,除此之外并无其他。
读写锁相关函数
读写锁的初始化(pthread_rwlock_init)
功能: 初始化读写锁
#include<pthread.h> int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthred_rwlockattr_t *restrict attr);
参数说明:
rwlock: 是要进行初始化的读写锁
attr:是rwlock的属性,此参数一般不关注,可设为NULL
读写锁的销毁(pthread_rwlock_destroy)
功能: 销毁初始化的锁
#include<pthread.h> int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
参数说明:
rwlock: 是需要进行销毁的锁
加读锁(pthread_rdlock_lock)
pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
加写锁(pthread_wrlock_lock)
pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);
读锁写锁的解锁(pthread_rwlock_unlock)
pthread_rwlock_unlock(pthread_rwlock_t* rwlock);
读者写者模型示例代码
运行结果:
让读者每隔100微秒读一次,让写者每隔90微秒写一次,时间间隔很短,有五个读者,因此能看到读者读数据较为频繁。
在这里的代码其实不是很符合读者写者模型,因为实际上读者写者模型中读者可能会读几分钟一直都在读,这里我们只是为了看到现象而加入了usleep函数来控制读者写者的速度。
这里运行速度太快啦(╯°Д°)╯!作者手速跟不上,我就截取小片段辽(✧◡✧)!
代码如下:
1 #include <iostream>
2 #include <pthread.h>
3 #include <unistd.h>
4 int data=0;
5 pthread_rwlock_t rwlock;
6 void *reader(void *arg)
7 {
8 while(1)
9 {
10 pthread_rwlock_rdlock(&rwlock);
11 std::cout<<"reader down:"<<data<<std::endl;
12 pthread_rwlock_unlock(&rwlock);
13 usleep(100);
14 }
15 }
16 void *writer(void *arg)
17 {
18 while(1)
19 {
20 pthread_rwlock_wrlock(&rwlock);
21 std::cout<<"writer down:"<<++data<<std::endl;
22 pthread_rwlock_unlock(&rwlock);
23 usleep(90);
24 }
25 }
26 int main()
27 {
28 pthread_rwlock_init(&rwlock,NULL);
29 pthread_t r[5],w;
30 pthread_create(&r[0],NULL,reader,NULL);
31 pthread_create(&r[1],NULL,reader,NULL);
32 pthread_create(&r[2],NULL,reader,NULL);
33 pthread_create(&r[3],NULL,reader,NULL);
34 pthread_create(&r[4],NULL,reader,NULL);
35 pthread_create(&w,NULL,writer,NULL);
36
37 int i=0;
38 for(i=0;i<5;i++)
39 {
40 pthread_join(r[i],NULL);
41 }
42 pthread_join(w,NULL);
43 pthread_rwlock_destroy(&rwlock);
44 return 0;
45 }