线程同步之读写锁

线程同步之读写锁

一、读写锁的原理

读写锁与互斥量类似,不过读写锁有更高的并行性。互斥量要么加锁要么不加锁,而且同一时刻只允许一个线程对其加锁。对于一个变量的读取,完全可以让多个线程同时进行操作 。

二、读写锁的状态

一把读写锁具备三种状态:

​ 1. 读模式下加锁状态 (读锁)

​ 2. 写模式下加锁状态 (写锁)

3. 不加锁状态

读写锁的特点如下:

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

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

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

举例子来说:

  • 线程A加写锁成功,线程B请求读锁
    • 线程B堵塞
  • 线程A持有读锁,线程B请求写锁
    • 线程B堵塞
  • 线程A拥有读锁,线程B请求读锁
    • 线程B加锁成功
  • 线程A持有读锁,然后线程B请求写锁,然后线程C请求读锁
    • B阻塞,C阻塞–写的优先级高
    • A解锁,B线程加锁成功,C堵塞
    • B解锁,C加读锁成功
  • 线程A持有写锁,然后线程B请求读锁,然后线程C请求写锁
    • BC堵塞
    • A解锁,C加写锁成功,B继续阻塞
    • C解锁,B加读锁成功

读写锁也叫共享-独占锁。当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。写独占、读共享。

三、函数

1)初始化读写锁

int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *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 错误码。

2)申请读锁

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);

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

3)申请写锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock );

功能:

在读写锁上获取写锁(写锁定)。如果没有写者持有该锁,并且没有写者读者持有该锁,则调用线程会获取写锁。如果调用线程未获取写锁,则它将阻塞直到它获取了该锁。

参数:

rwlock:读写锁指针。

返回值:

成功:0

失败:非 0 错误码

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

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

4)解锁

int pthread_rwlock_unlock (pthread_rwlock_t *rwlock);

功能:

无论是读锁或写锁,都可以通过此函数解锁。

参数:

rwlock:读写锁指针。

返回值:

成功:0

失败:非 0 错误码

5)销毁读写锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

功能:

用于销毁一个读写锁,并释放所有相关联的资源(所谓的所有指的是由 pthread_rwlock_init() 自动申请的资源) 。

参数:

rwlock:读写锁指针。

返回值:

成功:0

失败:非 0 错误码

代码实例:

 1 #include<stdio.h>                                                                     
  2 #include<unistd.h>
  3 #include<pthread.h>
  4 
  5 //读写锁
  6 pthread_rwlock_t rwlock;
  7 
  8 //全局变量
  9 int No = 1;
 10 
 11 //写操作
 12 void *fun1(void* arg)
 13 {
 14     while(1)
 15     {
 16         pthread_rwlock_wrlock(&rwlock);
 17         No++;
 18         printf("write thread \n");
 19         pthread_rwlock_unlock(&rwlock);
 20         sleep(2);
 21     }
 22 }
 23 
 24 
 25 //读操作
 26 void *fun2(void* arg)
 27 {
 28     while(1)
 29     {
 30         pthread_rwlock_rdlock(&rwlock);
 31         printf("first read thread :%d\n",No);
 32         pthread_rwlock_unlock(&rwlock);
 33         sleep(2);
 34     }
 35 }
 36 
 37 //读操作2                   
  38 void *fun3(void *arg)
 39 {
 40     while(1)
 41     {
 42         pthread_rwlock_rdlock(&rwlock);
 43         printf("second read thread:%d\n",No);
 44         pthread_rwlock_unlock(&rwlock);
 45         sleep(2);
 46     }
 47 }
 48 
 49 int main()
 50 {
 51     pthread_t tid1,tid2,tid3;
 52     //初始化读写锁
 53     pthread_rwlock_init(&rwlock, NULL);
 54 
 55     //创建线程                 
  56     pthread_create(&tid1,NULL,fun1,NULL);
 57     pthread_create(&tid2,NULL,fun2,NULL); 
 58     pthread_create(&tid3,NULL,fun3,NULL); 
 59     
 60     //回收资源
 61     pthread_join(tid1,NULL);
 62     pthread_join(tid2,NULL);
 63     pthread_join(tid3,NULL);
 64 
 65     //销毁读写锁
 66     pthread_rwlock_destroy(&rwlock);
 67 
 68     return 0;
 69 }                      

结果:

wz@wz-machine:~/linux$ ./rw_lock 
second read thread:1
first read thread :1
write thread 
first read thread :2
second read thread:2
write thread 
second read thread:3
first read thread :3
write thread 
first read thread :4
second read thread:4

我们试试没有加锁的现象:

把读写锁注释掉的结果是:

first read thread :3
second read thread:3
write thread 
second read thread:4
first read thread :4
write thread 
first read thread :5
second read thread:5
write thread 
second read thread:6
write thread 
first read thread :7
write thread 
first read thread :8
second read thread:8
first read thread :8
second read thread:8
write thread 

很明显我们可以看出来问题;数据混乱。

猜你喜欢

转载自blog.csdn.net/Travelerwz/article/details/81697348