Linux系统编程 | 读写锁

        在上一篇博客文章中已经对互斥锁进行了简单的梳理总结,本文接着前面的基础,继续扩充讲解读写锁

Linux系统编程 | 互斥锁-CSDN博客https://blog.csdn.net/weixin_49337111/article/details/148998849?spm=1001.2014.3001.5502

1、互斥锁的不足

        互斥锁无论是读取共享资源,还是修改共享资源,都要上锁,而是在上锁期间,不能被别的线程上锁。互斥锁使用非常简便,但他也有不适用的场合——假如要保护的共享资源在绝大多数的情况下是读操作,就会导致这些本可以一起读的线程阻塞在互斥锁上,资源得不到最大的利用。

        互斥锁的低效率,是因为没有更加细致地区分如何访问共享资源,一刀切地在任何时候都只允许一条线程访问共享资源,而事实情况是读操作可以同时进行只有写操作才需要互斥,因此如果能根据访问的目的——或者,来分别加读锁(可以重复加)或者写锁(只允许一次一个),就能就能极大地提高效率(尤其是存在大量读操作的情况下)。

2、什么是读写锁

        访问资源(一起读一本书) -> 同时上读锁 -> 读锁就是一把共享锁

        修改资源(一起做试卷) -> 不能同时上写锁 -> 写锁就是一把互斥锁

        这把既有读锁,又有写锁的锁,就称之为读写锁。

        基于互斥锁在的不足,提出了读写锁。读写锁允许多个线程同时读取共享资源,但在写入共享资源时只允许一个线程进行。它把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,因为读操作本身是线程安全的,而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的。

        读写锁提高了程序执行性能:多个读锁可以同时执行,相比于普通锁在任何情况下都要排队执行来说,读写锁提高了程序的执行性能。

        读写锁避免读到临时数据锁和锁是互斥排队执行的,这样可以保证了读取操作不会读到写了一半的临时数据。

3、读写锁API接口

(1)、定义一个读写锁变量

        数据类型: pthread_rwlock_t

pthread_rwlock_t rwlock;

(2)、初始化读写锁

        读写锁允许多个线程同时读取共享数据,但写入时需要独占访问,适用于读多写少的场景。

#include <pthread.h>

int pthread_rwlock_init(pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attr);

参数:
    rwlock:指向需要初始化的读写锁对象变量地址
    attr:指向读写锁的属性对象变量地址,一般为NULL,表示默认属性
    
返回值:
    成功:0
    失败:非0错误码

(3)、读锁上锁

#include <pthread.h>

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

参数:
    rwlock:指向已初始化的读写锁对象变量地址
    
返回值:
    成功:0
    失败:非0错误码

(4)、写锁上锁

#include <pthread.h>

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

参数:
    rwlock:指向已初始化的读写锁对象变量地址
    
返回值:
    成功:0
    失败:非0错误码

(5)、读写锁解锁

        读写锁分为读锁(共享)和写锁(独占),pthread_rwlock_unlock 可以释放当前线程持有的任意一种锁。

#include <pthread.h>

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

参数:
    rwlock:指向已初始化的读写锁对象变量地址
    
返回值:
    成功:0
    失败:非0错误码

(6)、销毁读写锁

        释放读写锁占用的资源,使其不再可用。

#include <pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

参数:
    rwlock:指向已初始化的读写锁对象变量地址
    
返回值:
    成功:0
    失败:非0错误码

4、读写锁的应用

        在上一篇博客里面,通过互斥锁实现了各个线程依次对变量进行读写操作,但也可以发现,各个线程中,读与写发生了冲突,不同线程之间进行数据读取任务,操作时都会进行互斥。因此这里使用读写锁对上文的程序代码进行改进

#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>
#include <sys/sem.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>



//定义一个读写锁变量
pthread_rwlock_t rwlock;

int g_val = 10;


void *start_routine1(void *arg)
{
    pthread_rwlock_wrlock(&rwlock);//加写锁
    
    g_val = 20;
    sleep(3);
    printf("start_routine1: %d\n",g_val);
    
    pthread_rwlock_unlock(&rwlock); //解锁
}

void *start_routine2(void *arg)
{
    pthread_rwlock_wrlock(&rwlock);//加写锁
    g_val = 200;
    sleep(3);
    printf("start_routine2: %d\n",g_val);
    
    pthread_rwlock_unlock(&rwlock); //解锁
}

void *start_routine3(void *arg)
{
    pthread_rwlock_rdlock(&rwlock);//加读锁
    
    //获取数据 访问(读取) 共享资源 但是没有进行修改(写入)
    int cnt=5;
    while(cnt--)
    {
        sleep(1);
        printf("start_routine3: %d\n",g_val);
    }
    
    pthread_rwlock_unlock(&rwlock); //解锁
}

void *start_routine4(void *arg)
{
    pthread_rwlock_rdlock(&rwlock);//加读锁
    
    //获取数据 访问(读取) 共享资源 但是没有进行修改(写入)
    int cnt=5;
    while(cnt--)
    {
        sleep(1);
        printf("start_routine4: %d\n",g_val);
    }
        
    pthread_rwlock_unlock(&rwlock); //解锁
}

int main(int argc, char **argv)
{
    //初始化读写锁
    pthread_rwlock_init(&rwlock,NULL);

    pthread_t thread1;
    pthread_create(&thread1,NULL,start_routine1, NULL);    
    pthread_t thread2;
    pthread_create(&thread2,NULL,start_routine2, NULL);
    pthread_t thread3;
    pthread_create(&thread3,NULL,start_routine3, NULL);
    pthread_t thread4;
    pthread_create(&thread4,NULL,start_routine4, NULL);    
    
    
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    pthread_join(thread3, NULL);
    pthread_join(thread4, NULL);
       
    //销毁读写锁
    pthread_rwlock_destroy(&rwlock);

    return 0;
}

        读写锁运行结果如下图所示,线程1、线程3、线程4正常进行数据读取,线程2进行数据写入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值