计算机操作系统基础 (十三)--- 线程同步之读写锁

用户头像
书旅
关注
发布于: 2020 年 07 月 06 日
计算机操作系统基础(十三)---线程同步之读写锁

引言

本文为第十三篇,线程同步之读写锁,读写锁也是解决线程同步的方法之一,在前边的两篇文章中国已经介绍了互斥量和自旋锁两种方法。读写锁的原理也和前边两种锁类似,但是读写锁做了一些改进



读写锁

读写锁的改进是从以下几个点进行考量的,其中最重要的是对临界资源的考量。在复杂的开发环境中,很可能会出现对临界资源多读少写的情况。比如说一个数据库中的表,存储的主要是一些历史数据,对于这些历史数据,一般都是进行查询,很少进行修改,那么这个存储历史数据的表就属于多读少写的临界资源。对于读取的时候并不会改变临界资源的值,如果我们每一次去读或者写的时候都给它加锁,这样效率是很低的。那么这个时候就应该考虑是否有效率更高的方法?这个时候就产生了读写锁



读写锁介绍

  • 读写锁是一种特殊的自旋锁

  • 允许多个读者同时访问资源,以提高读性能

  • 对于写操作是互斥的(不允许多个写操作同时访问同一资源)



关于读写锁的模型



对于读写锁,它允许多个读者同时去读取临界资源,因此下图中的读线程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/class.syncreaderwriter.php



在快速变化的技术中寻找不变,才是一个技术人的核心竞争力。知行合一,理论结合实践





发布于: 2020 年 07 月 06 日 阅读数: 35
用户头像

书旅

关注

公众号:IT猿圈 2019.04.11 加入

还未添加个人简介

评论

发布
暂无评论
计算机操作系统基础(十三)---线程同步之读写锁