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

48次阅读

共计 2560 个字符,预计需要花费 7 分钟才能阅读完成。

引言

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

读写锁

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

读写锁介绍

  • 读写锁是一种特殊的自旋锁
  • 允许多个读者同时访问资源,以提高读性能
  • 对于写操作是互斥的(不允许多个写操作同时访问同一资源)

关于读写锁的模型

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

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

正文完
 0