Linux学习之系统编程篇:读写锁(pthread_ rwlock _init / rdlock / wrlock / unlock / destroy)

一、读写锁的认识

(1)读写锁是1把锁。
(2)读写锁的类型: pthread_rwlock_t lock 又分“读锁”(不让读内存)和“写锁”(不让写内存)
(3)读写锁的特性:
1)读共享:例如,线程 A 加读锁成功,有来个 3 个线程,作读操作,也可加锁成功。
2)写独占:例如,线程 A 加读写成功,有来个 3 个线程,作读操作,3 个线程阻塞。
3) 读写不能同时进行,写的优先级高。
说明 1:线程 A 加读写成功,然后进程 B 加写锁,因为读写不能同时进行,会写阻塞。
说明 2:此时又来了 C 线程加读锁,因为已经写阻塞,写的优先级高,遵照写独占,会读阻塞。
(4)读写锁的场景练习:
1)线程 A 加写锁成功,线程 B 请求读锁 :B 读阻塞。
2)线程 A 加读锁成功,线程 B 请求写锁 :B 写阻塞。
3)线程 A 加读锁成功,线程 B 请求读锁 :线程 B 加读锁成功。
4)线程 A 加读锁成功,然后线程 B 请求写锁,然后线程 C 请求读锁 :B 写阻塞,C 读阻塞;
A 解锁 :B 加写锁成功,C 继续读阻塞 ;
B 解锁 :C 加读锁成功。
5)线程 A 加读写成功,然后线程 B 请求读锁,然后线程 C 请求写锁 :B 读阻塞,C 写阻塞;
A 解锁 :C 加写锁成功,B 继续读阻塞;
C 解锁 :B 加读锁成功。
(5)读写锁适用的场景
互斥锁 : 读写串行 。
读写锁 : 读并行,写串行。
读写锁更关注“读并行”,如果关注串行,那直接用互斥锁好了,所以读写锁更适用于读操作多的场景,通过其并行的特性,可以提高效率。

二、读写锁的操作函数(用法基本跟互斥锁相同)

读写锁函数的返回值都是:成功返回 0, 失败直接返回错误号。

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

(1)初始化一个读写锁
函数说明:

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

使用:

pthread_rwlock_init( &rwlock, NULL);

(2)请求读锁
函数说明:

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

使用:

pthread_rwlock_rdlock ( &rwlock);

注意:之前有读锁,可以加锁成功;之前有写锁,此时加读锁失败,不返回,会读阻塞。
(3)请求写锁
函数说明:

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

使用:

pthread_rwlock_wrlock ( &rwlock);

注意:之前只要加锁,就阻塞(之前加读锁,读锁和写锁不能同时存在; 之前加写锁,写独享)。
(4)
1)非阻塞请求读锁
函数说明:

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

注意:之前有读锁,可以加成功,返回 0;之前有写锁,加读锁失败,直接返回错误号,不阻塞
2)非阻塞请求写锁

int pthread_rwlock_tryrwrock(pthread_rwlock_t *rwlock);

注意:之前没锁,可以加锁成功,返回 0;之前有锁,无论读写,直接返回错误号,不阻塞。
(5)解锁:
函数说明:

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

使用:

pthread_rwlock_unlock ( &rwlock);

(6)销毁读写锁:
函数说明:

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

使用:

pthread_rwlock_destroy ( &rwlock);

三、读写锁练习

需求:3 个线程不定时对同一个全局变量作写操作,5 个线程不定时对同一全局变量作读操作

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
int number = 0; // 定义一个全局变量
pthread_rwlock_t rwlock; // 定义一把读写锁
void* write_func() // 写线程回调函数
{
 while(1)
 {
 pthread_rwlock_wrlock(&rwlock); // 请求写锁
 number++;
 printf("write_pthread: %lu, number = %d\n", pthread_self(), number);
 pthread_rwlock_unlock(&rwlock); // 开锁
 usleep(500); // 防止写太快
 }
 return NULL; }
void* read_func() // 读线程回调函数
{
 while(1)
 {
 pthread_rwlock_rdlock(&rwlock); // 请求读锁
 printf("read_pthread: %lu, number = %d\n", pthread_self(), number);
 pthread_rwlock_unlock(&rwlock); // 开锁
 usleep(500); // 防止读太快
 }
 return NULL; }
int main()
{
 pthread_rwlock_init(&rwlock, NULL); // 初始化读写锁
 pthread_t p[8];
 //创建3个写线程
 for(int i = 0; i < 3; i++)
 {
 pthread_create(&p[i], NULL, write_func, NULL);
 }
 //创建5个写线程
 for(int i = 3; i < 8; i++)
 {
 pthread_create(&p[i], NULL, read_func, NULL);
 }
 // 阻塞回收子线程的pcb
 for(int i = 0; i < 8; i++)
 {
 pthread_join(p[i], NULL);
 }
 // 销毁读写锁
 pthread_rwlock_destroy(&rwlock);
 return 0; 
}

截取一些结果片段:
write_pthread: 139701616846592, number = 4127
write_pthread: 139701625239296, number = 4128
write_pthread: 139701608453888, number = 4129
read_pthread: 139701503641344, number = 4129
read_pthread: 139701528819456, number = 4129
read_pthread: 139701495248640, number = 4129
read_pthread: 139701520426752, number = 4129
read_pthread: 139701512034048, number = 4129
write_pthread: 139701625239296, number = 4130
read_pthread: 139701528819456, number = 4130
现象:先写后,number 的值的由小到大,并且写操作的数值是连续的,顺序并不混乱。
说明:如果不加锁,会出现数据混乱(读的 number 比写的 number 大,显然不符合常规理解)。

  • 10
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在基于 rt-thread 的系统中,可以使用 `struct rt_semaphore` 结构体来实现的控制。具体实现可以参考以下代码: ``` struct rt_semaphore rw_sem; int read_count; /* 初始化 */ int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) { /* 初始化信号量,初始值为 1 */ rt_sem_init(&rw_sem, "rw_sem", 1, RT_IPC_FLAG_FIFO); read_count = 0; return 0; } /* 销毁 */ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) { /* 删除信号量 */ rt_sem_delete(&rw_sem); return 0; } /* 对进行定 */ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) { /* 获取信号量,如果信号量值为 0,则线程阻塞 */ rt_sem_take(&rw_sem, RT_WAITING_FOREVER); read_count++; return 0; } /* 对进行定 */ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) { /* 获取信号量,如果信号量值为 0,则线程阻塞 */ rt_sem_take(&rw_sem, RT_WAITING_FOREVER); while (read_count > 0) { /* 如果有线程在使用,则等待线程全部释放 */ rt_sem_release(&rw_sem); rt_sem_take(&rw_sem, RT_WAITING_FOREVER); } return 0; } /* 对进行解 */ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) { /* 释放信号量 */ rt_sem_release(&rw_sem); read_count--; return 0; } ``` 在上述代码中,我们使用了一个信号量来实现的控制。信号量的初始值为 1,表示是未定状态。当线程需要对进行定时,首先需要获取信号量,如果信号量的值为 0,则线程阻塞等待。对于,只需要将计数器 `read_count` 加 1 即可;对于,则需要判断是否有线程在使用,如果有,则等待线程全部释放后再获取。对于解操作,只需要释放信号量并将计数器减 1 即可。 上述代码中的函数名和参数与 POSIX 标准中定义的函数名和参数保持一致,因此可以直接调用这些函数来实现的控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值