以前总是以为读写锁是两把锁,感觉这个和进程的管道通信差不多。既然进程有读端和写端,那么想当然的就认为读写锁就是读锁和写锁两把锁,接触到这个概念后才觉得自己还是flag立得太早了
相关概念
- 读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。
特性
- 线程A加读锁成功,线程B,C加读锁,可以加锁成功
- 线程A加写锁成功,线程B,C加读锁,B,C阻塞。
- 线程A加读锁成功,线程B加写锁阻塞,C线程加读锁阻塞。
上面的特性我们可以概括为读的共享性,写的独占性 即读操作是并行的,写操作是串行的,并且写操作的优先级要高于读操作。
相关函数
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); //初始化锁
//清除锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
//加读锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
//加写锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
//解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
读写锁与互斥锁的区别
- 读写锁允许多个线程同时对共享数据进行读操作,写操作互斥。
- 互斥锁一次只允许有一个线程拥有互斥锁,并对数据进行访问。
读写锁的简单实现
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
int num = 0; //共享数据
pthread_rwlock_t lock; //声明读写锁
void * wr_func(void * arg)
{
int count = 10; //控制循环次数
while(count--)
{
pthread_rwlock_wrlock(&lock); //加写锁
num++;
printf("==写线程%lu写入%d\n",pthread_self(),num);
pthread_rwlock_unlock(&lock); //解锁
usleep(400);
}
return NULL;
}
void * rd_func(void * arg)
{
int count = 10;
while(count--)
{
pthread_rwlock_rdlock(&lock); //加读锁
printf("--读线程%lu获取%d\n",pthread_self(),num);
pthread_rwlock_unlock(&lock); //解锁
usleep(400);
}
return NULL;
}
int main (void)
{
pthread_t thid[10];
pthread_rwlock_init(&lock,NULL); //初始化读写锁
for(int i = 0;i<4;i++)
pthread_create(&thid[i],NULL,(void*)&wr_func,NULL);
for(int i = 4;i<10;i++)
pthread_create(&thid[i],NULL,(void*)&rd_func,NULL);
for(int i = 0;i< 10;i++)
pthread_join(thid[i],NULL);
pthread_rwlock_destroy(&lock); //清除读写锁,释放资源
return 0;
}
输出结果(片段):
读操作每次所读数据都是最新的。
文章难免会有所疏漏和不足的地方,如果有错误,欢迎小伙伴指正。