引言
本文为第十三篇,线程同步之读写锁,读写锁也是解决线程同步的方法之一,在前边的两篇文章中国已经介绍了互斥量和自旋锁两种方法。读写锁的原理也和前边两种锁类似,但是读写锁做了一些改进
读写锁
读写锁的改进是从以下几个点进行考量的,其中最重要的是对临界资源的考量。在复杂的开发环境中,很可能会出现对临界资源多读少写的情况。比如说一个数据库中的表,存储的主要是一些历史数据,对于这些历史数据,一般都是进行查询,很少进行修改,那么这个存储历史数据的表就属于多读少写的临界资源。对于读取的时候并不会改变临界资源的值,如果我们每一次去读或者写的时候都给它加锁,这样效率是很低的。那么这个时候就应该考虑是否有效率更高的方法?这个时候就产生了读写锁
读写锁介绍
- 读写锁是一种特殊的自旋锁
- 允许多个读者同时访问资源,以提高读性能
- 对于写操作是互斥的(不允许多个写操作同时访问同一资源)
关于读写锁的模型
对于读写锁,它允许多个读者同时去读取临界资源,因此下图中的读线程1、2、3可以同时读取临界资源,但是在读取的同时,它不会允许写操作去访问临界资源。因为读取的时候并不会改变临界资源,而写操作可能会改变临界资源的值,因此在读写锁中读和写是互斥的,读和读之间是不互斥的
读写锁示例
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#include<vector>//临界资源int num=0;//定义读写锁pthread_rwlock_t relock=PTHREAD_RWLOCK_INITIALIZER;void *reader(void*){ int times=10000000; while(times--){ //在读操作之前加读锁 pthread_rwlock_rdlock(&rdlock); if(times%1000==0){ usleep(10); } //释放读锁 pthread_rwlock_unlock(&rdlock); }}void *writer(void*){ int times=10000000; while(times--){ //加写锁 pthread_rwlock_wrlock(&rdlock); num+=1; pthread_rwlock_unlock(&rdlock); }}int main(){ printf("Start in main function."); //定义三个线程 pthread_t thread1,thread2, thread3; //两个执行读操作,一个执行写操作 pthread_create(&thread1, NULL, &reader, NULL); pthread_create(&thread2, NULL, &reader, NULL); pthread_create(&thread3, NULL, &writer, NULL); pthread_join(&thread1, NULL); pthread_join(&thread2, NULL); pthread_join(&thread3, NULL); //打印临界资源的值 printf("Print in main function: num = %d\n", num); return 0;}
因为上边提到,读写锁对于多读少写的情况下,会有很明显的性能提升的,此时就可以验证一下,运行上边使用的读写锁的程序,查看运行时间如下:
现在将读写锁换成互斥量,然后看一下执行时间
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#include<vector>//临界资源int num=0;//初始化互斥量pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//定义读写锁//pthread_rwlock_t relock=PTHREAD_RWLOCK_INITIALIZER;void *reader(void*){ int times=10000000; while(times--){ //在读操作之前加读锁 //pthread_rwlock_rdlock(&rdlock); pthread_mutex_lock(&mutex); if(times%1000==0){ usleep(10); } //释放读锁 //pthread_rwlock_unlock(&rdlock); pthread_mutex_unlock(&mutex); }}void *writer(void*){ int times=10000000; while(times--){ //加写锁 //pthread_rwlock_wrlock(&rdlock); pthread_mutex_lock(&mutex); num+=1; //pthread_rwlock_unlock(&rdlock); pthread_mutex_unlock(&mutex); }}int main(){ printf("Start in main function."); //定义三个线程 pthread_t thread1,thread2, thread3; //两个执行读操作,一个执行写操作 pthread_create(&thread1, NULL, &reader, NULL); pthread_create(&thread2, NULL, &reader, NULL); pthread_create(&thread3, NULL, &writer, NULL); pthread_join(&thread1, NULL); pthread_join(&thread2, NULL); pthread_join(&thread3, NULL); //打印临界资源的值 printf("Print in main function: num = %d\n", num); return 0;}
执行结果:
可以看见,对于多读少写的临界资源,使用读写锁的效率是使用互斥量的大概5倍
PHP中读写锁相关API:https://www.php.net/manual/zh...
在快速变化的技术中寻找不变,才是一个技术人的核心竞争力。知行合一,理论结合实践