前面介绍过Linux多线程同步的另外两个方法------互斥锁和信号量
Linux多线程的同步-----信号量和互斥锁_神厨小福贵!的博客-优快云博客
下面来看一下读写锁:
读写锁和互斥锁都带有一个锁,那么他们有什么区别呢?
读写锁 | 互斥锁 |
多个读操作可以同时进行 | 一次只有一个线程拥有互斥锁,其他线程只有等待 |
写操作之间必须互斥 | |
读写操作之间也是互斥的,且写操作的应优先于读操作(写操作执行的时候,其他函数都在阻塞) |
上面说到了读写锁和互斥锁的区别,相信大家对读写锁已经有了一定的理解,下面来看读写锁所用到的函数以及头文件:
头文件:#include <pthread.h>
读写锁初始化函数:
int pthread_rwlock_init(pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr);
第一个参数是读写锁指针,第二个参数是读写锁的属性的指针(一般置为NULL)----下面附上官方手册
读锁:int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
写锁:int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
解锁:int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
销毁锁:int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
函数里面的参数都是所创建的读写锁的指针
下面来看一个代码示例:下面代码是没有加读写锁🔓的代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
pthread_rwlock_t rwlock;//读写锁的创建
void * read_fun1(void * arg) //读子线程的函数
{
while(1)
{
printf("read1 start \n");
sleep(1);
printf("read2 end \n");
}
}
void * read_fun2(void * arg)
{
while(1)
{
printf("read2 start \n");
sleep(1);
printf("read2 end \n");
}
}
void * write_fun(void * arg)
{
while(1)
{
printf("write start \n");
sleep(1);
printf("write end \n");
}
}
int main()
{
pthread_rwlock_init(&rwlock,NULL);
pthread_t idr1,idr2; //创建两个读的线程
pthread_t idw; //创建一个写的线程
pthread_create(&idr1,NULL,read_fun1,NULL);
pthread_create(&idr2,NULL,read_fun2,NULL);
pthread_create(&idw,NULL,write_fun,NULL);
pthread_join(idr1,NULL);
pthread_join(idr2,NULL);
pthread_join(idw,NULL);
pthread_rwlock_destroy(&rwlock);
exit(0);
}
~
上面代码没有加读写锁,我们来运行结果:
运行结果可看出,在读操作进行的同时,写操作也在进行着,那么我们再来看一下加了读写锁之后的运行结果
来看加了读写锁之后的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
pthread_rwlock_t rwlock;//读写锁的创建
void * read_fun1(void * arg) //读子线程的函数
{
while(1)
{
pthread_rwlock_rdlock(&rwlock); //对读操作枷锁
printf("read1 start \n");
sleep(1);
printf("read2 end \n");
pthread_rwlock_unlock(&rwlock); //读完进行解锁
}
}
void * read_fun2(void * arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock); //对读操作枷锁
printf("read2 start \n");
sleep(1);
printf("read2 end \n");
pthread_rwlock_unlock(&rwlock); //读完进行解锁
}
}
void * write_fun(void * arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock); //对写操作枷锁
printf("write start \n");
sleep(1);
printf("write end \n");
pthread_rwlock_unlock(&rwlock); //写完进行解锁
}
}
int main()
{
pthread_rwlock_init(&rwlock,NULL);
pthread_t idr1,idr2; //创建两个读的线程
pthread_t idw; //创建一个写的线程
pthread_create(&idr1,NULL,read_fun1,NULL);
pthread_create(&idr2,NULL,read_fun2,NULL);
pthread_create(&idw,NULL,write_fun,NULL);
pthread_join(idr1,NULL);
pthread_join(idr2,NULL);
pthread_join(idw,NULL);
pthread_rwlock_destroy(&rwlock);
exit(0);
}
~
加了锁之后再来运行 看结果:
看了结果发现,诶,怎么还是不对啊,怎么没有写操作呢?
在我上面的代码中,是读操作的线程创建函数先于写操作的线程创建函数,然后刚开始就是读拿锁,又因为读操作是可以同时拿锁的,所以两个读操作同时拿锁,中间可能会有间隔 ,但是这个间隔时间之中是另外一个读操作在拿锁,所以写操作就一直拿不到锁,但是你只要给每次解锁之后加个睡眠一秒钟的函数,就会改善这种情况
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
pthread_rwlock_t rwlock;//读写锁的创建
void * read_fun1(void * arg) //读子线程的函数
{
while(1)
{
pthread_rwlock_rdlock(&rwlock); //对读操作枷锁
printf("read1 start \n");
sleep(1);
printf("read2 end \n");
pthread_rwlock_unlock(&rwlock); //读完进行解锁
sleep(1);
}
}
void * read_fun2(void * arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock); //对读操作枷锁
printf("read2 start \n");
sleep(1);
printf("read2 end \n");
pthread_rwlock_unlock(&rwlock); //读完进行解锁
sleep(1);
}
}
void * write_fun(void * arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock); //对写操作枷锁
printf("write start \n");
sleep(1);
printf("write end \n");
pthread_rwlock_unlock(&rwlock); //写完进行解锁
sleep(1);
}
}
int main()
{
pthread_rwlock_init(&rwlock,NULL);
pthread_t idr1,idr2; //创建两个读的线程
pthread_t idw; //创建一个写的线程
pthread_create(&idr1,NULL,read_fun1,NULL);
pthread_create(&idr2,NULL,read_fun2,NULL);
pthread_create(&idw,NULL,write_fun,NULL);
pthread_join(idr1,NULL);
pthread_join(idr2,NULL);
pthread_join(idw,NULL);
pthread_rwlock_destroy(&rwlock);
exit(0);
}
加上睡眠函数之后的运行结果:
就可以了,这是因为在读完数据之后,间隔那一秒钟,读操作空闲不拿锁的时候,那个写操作就可以拿到锁子,但是这玩意说到底的优先级是什么,别人做过实验,结果是写操作优先: