Linux网络编程【读写锁】

举报
xcc-2022 发表于 2022/10/24 21:01:26 2022/10/24
【摘要】 04. 读写锁 4.1 读写锁概述当有一个线程已经持有互斥锁时,互斥锁将所有试图进入临界区的线程都阻塞住。但是考虑一种情形,当前持有互斥锁的线程只是要读访问共享资源,而同时有其它几个线程也想读取这个共享资源,但是由于互斥锁的排它性,所有其它线程都无法获取锁,也就无法读访问共享资源了,但是实际上多个线程同时读访问共享资源并不会导致问题。在对数据的读写操作中,更多的是读操作,写操作较少,例如对...

04. 读写锁

4.1 读写锁概述

当有一个线程已经持有互斥锁时,互斥锁将所有试图进入临界区的线程都阻塞住。但是考虑一种情形,当前持有互斥锁的线程只是要读访问共享资源,而同时有其它几个线程也想读取这个共享资源,但是由于互斥锁的排它性,所有其它线程都无法获取锁,也就无法读访问共享资源了,但是实际上多个线程同时读访问共享资源并不会导致问题。

在对数据的读写操作中,更多的是读操作,写操作较少,例如对数据库数据的读写应用。为了满足当前能够允许多个读出,但只允许一个写入的需求,线程提供了读写锁来实现。

image-20220927124322089

读写锁的特点如下:

1)如果有其它线程读数据,则允许其它线程执行读操作,但不允许写操作。

2)如果有其它线程写数据,则其它线程都不允许读、写操作。

读写锁分为读锁和写锁,规则如下:

1)如果某线程申请了读锁,其它线程可以再申请读锁,但不能申请写锁。

2)如果某线程申请了写锁,其它线程不能申请读锁,也不能申请写锁。

POSIX 定义的读写锁的数据类型是: pthread_rwlock_t。

4.2 pthread_rwlock_init函数

#include <pthread.h>

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
    const pthread_rwlockattr_t *restrict attr);
功能:
    用来初始化 rwlock 所指向的读写锁。

参数:
    rwlock:指向要初始化的读写锁指针。
    attr:读写锁的属性指针。如果 attr 为 NULL 则会使用默认的属性初始化读写锁,否则使用指定的 attr 初始化读写锁。

    可以使用宏 PTHREAD_RWLOCK_INITIALIZER 静态初始化读写锁,比如:
    pthread_rwlock_t my_rwlock = PTHREAD_RWLOCK_INITIALIZER;

    这种方法等价于使用 NULL 指定的 attr 参数调用 pthread_rwlock_init() 来完成动态初始化,不同之处在于PTHREAD_RWLOCK_INITIALIZER 宏不进行错误检查。

返回值:
    成功:0,读写锁的状态将成为已初始化和已解锁。
    失败:非 0 错误码。

4.3 pthread_rwlock_destroy函数

#include <pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
功能:
    用于销毁一个读写锁,并释放所有相关联的资源(所谓的所有指的是由 pthread_rwlock_init() 自动申请的资源) 。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

4.4 pthread_rwlock_rdlock函数

#include <pthread.h>

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
功能:
    以阻塞方式在读写锁上获取读锁(读锁定)。
    如果没有写者持有该锁,并且没有写者阻塞在该锁上,则调用线程会获取读锁。
    如果调用线程未获取读锁,则它将阻塞直到它获取了该锁。一个线程可以在一个读写锁上多次执行读锁定。
    线程可以成功调用 pthread_rwlock_rdlock() 函数 n 次,但是之后该线程必须调用 pthread_rwlock_unlock() 函数 n 次才能解除锁定。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
   用于尝试以非阻塞的方式来在读写锁上获取读锁。
   如果有任何的写者持有该锁或有写者阻塞在该读写锁上,则立即失败返回。

4.5 pthread_rwlock_wrlock函数

#include <pthread.h>

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
功能:
    在读写锁上获取写锁(写锁定)。
    如果没有写者持有该锁,并且没有写者读者持有该锁,则调用线程会获取写锁。
    如果调用线程未获取写锁,则它将阻塞直到它获取了该锁。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
   用于尝试以非阻塞的方式来在读写锁上获取写锁。
   如果有任何的读者或写者持有该锁,则立即失败返回。

4.6 pthread_rwlock_unlock函数

#include <pthread.h>

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
功能:
    无论是读锁或写锁,都可以通过此函数解锁。
参数:
    rwlock:读写锁指针。
返回值:
    成功:0
    失败:非 0 错误码

4.7 读写锁应用示例

下面是一个使用读写锁来实现 8个线程读写一段数据是实例。

在此示例程序中,共创建了 8 个线程,其中3个线程用来写入数据,5个线程用来读取数据。当某个线程读操作时,其他线程允许读操作,却不允许写操作;当某个线程写操作时,其它线程都不允许读或写操作。:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>

//读写锁案例
int num = 0;//全局变量
pthread_rwlock_t rwlock;

//读线程
void* read_fun(void *arg)
{
    int index = (int)(long)arg;
    while(1)
    {
         //加读写锁读锁
        pthread_rwlock_rdlock(&rwlock);
        printf("线程%d 读取num的值:%d\n",index,num);
        
        //解锁
        pthread_rwlock_unlock(&rwlock);
        //随机休眠1-3秒
        sleep(random()%3+1);
    }
    return NULL;
}
//写进程
void* write_fun(void* arg)
{ 
    int index = (int)(long)arg;
    while(1)
    {
        //加读写锁写锁
        pthread_rwlock_rdlock(&rwlock);
        num++;
        printf("线程%d 修改num的值:%d\n",index,num);
        
        //解锁
        pthread_rwlock_unlock(&rwlock);
        //随机休眠1-3秒
        sleep(random()%3+1);
    }
    return NULL;
}
int main()
{
    pthread_t tid[8];
    int ret = -1;
    int i = 0;

    //设置随即种子
    srandom(getpid());

    //初始化读写锁
    ret = pthread_rwlock_init(&rwlock,NULL);
    if(ret != 0)
    {
        printf("pthread_rwlock_init failed...\n");
        return 1;
    }
    //创建8个线程
    for(i=0; i<8; i++)
    {
        //5个读线程
        if(i<5)
        {
           ret = pthread_create(&tid[i],NULL,read_fun,(void*)(long)i);
           if(ret != 0)
           {
               printf("pthread_create falied...\n");
               return 1;
           }
        }
        else
        {
           //3个写线程
           ret = pthread_create(&tid[i],NULL,write_fun,(void*)(long)i);
           if(ret != 0)
           {
               printf("pthread_create falied...\n");
               return 1;
           }
        }
    }

    //回收8个线程资源
    for(i = 0; i<8 ;i++)
    {
         pthread_join(tid[i],NULL);
    }
    //销毁读写锁
    pthread_rwlock_destroy(&rwlock);

    return 0;
}
动画9
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。