linux读写锁
一.概述
读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区,读写锁比它有更高的并行性。读写锁有以下特点:
1.如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿!
2.如果一个线程用写锁锁住了临界区,那么其他线程不管是读锁还是写锁都会发生阻塞!
读写锁的优势往往展现在读操作很频繁,而写操作较少的情况下
二.函数接口
1.创建读写锁
1.1:宏常量初始化
1 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
1.2:函数初始化
1 #include <pthread.h> 2 3 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
rwlock:读写锁的pthread_rwlock_t结构指针
attr:读写锁的属性结构指针。不需要别的属性默认为NULL。
2.读写锁加锁与解锁
1 #include <pthread.h> 2 3 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); 4 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); 5 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
rwlock:创建的读写锁指针
3.其他类型的加锁
1 #include <pthread.h> 2 #include <time.h> 3 4 5 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); 6 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); 7 8 int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout); 9 int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
try类函数加锁:如果获取不到锁,会立即返回错误EBUSY!
timed类函数加锁:如果规定的时间内获取不到锁,会返回ETIMEDOUT错误!
4.销毁读写锁
#include <pthread.h> int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
应用实例:
创建4个线程,2个线程读锁,2个线程写锁,观察4个线程进入临界区的顺序:
1 /** 2 * * @file pthread_rwlock.c 3 * */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include <pthread.h> 10 using namespace std; 11 /* 初始化读写锁 */ 12 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 13 /* 全局资源 */ 14 class CSingle{ 15 public: 16 static CSingle& instance(){ 17 static CSingle single; 18 return single; 19 } 20 void setX(int y){ 21 this->x = y; 22 } 23 int getX(){ 24 return this->x; 25 } 26 int x; 27 }; 28 int global_num = 10; 29 30 void err_exit(const char *err_msg) 31 { 32 printf("error:%s\n", err_msg); 33 exit(1); 34 } 35 36 /* 读锁线程函数 */ 37 void *thread_read_lock(void *arg) 38 { 39 char *pthr_name = (char *)arg; 40 41 while (global_num) 42 { 43 /* 读加锁 */ 44 pthread_rwlock_rdlock(&rwlock); 45 46 printf("线程%s进入临界区,global_num = %d, X:%d\n", pthr_name, global_num, CSingle::instance().getX()); 47 sleep(1); 48 printf("线程%s离开临界区...\n", pthr_name); 49 50 /* 读解锁 */ 51 pthread_rwlock_unlock(&rwlock); 52 53 sleep(1); 54 } 55 56 return NULL; 57 } 58 59 /* 写锁线程函数 */ 60 void *thread_write_lock(void *arg) 61 { 62 char *pthr_name = (char *)arg; 63 64 while (global_num) 65 { 66 /* 写加锁 */ 67 pthread_rwlock_wrlock(&rwlock); 68 69 /* 写操作 */ 70 --global_num; 71 CSingle::instance().setX(global_num); 72 printf("线程%s进入临界区,global_num = %d, X:%d\n", pthr_name, global_num, CSingle::instance().getX()); 73 sleep(1); 74 printf("线程%s离开临界区...\n", pthr_name); 75 76 /* 写解锁 */ 77 pthread_rwlock_unlock(&rwlock); 78 79 sleep(2); 80 } 81 82 return NULL; 83 } 84 85 int main(void) 86 { 87 pthread_t tid_read_1, tid_read_2, tid_write_1, tid_write_2; 88 89 /* 创建4个线程,2个读,2个写 */ 90 if (pthread_create(&tid_read_1, NULL, thread_read_lock, (void *)"read_1") != 0) 91 err_exit("create tid_read_1"); 92 93 if (pthread_create(&tid_read_2, NULL, thread_read_lock, (void *)("read_2")) != 0) 94 err_exit("create tid_read_2"); 95 96 if (pthread_create(&tid_write_1, NULL, thread_write_lock, (void *)("write_1")) != 0) 97 err_exit("create tid_write_1"); 98 99 if (pthread_create(&tid_write_2, NULL, thread_write_lock, (void *)("write_2")) != 0) 100 err_exit("create tid_write_2"); 101 102 /* 随便等待一个线程,防止main结束 */ 103 if (pthread_join(tid_read_1, NULL) != 0) 104 err_exit("pthread_join()"); 105 if (pthread_join(tid_read_2, NULL) != 0) 106 err_exit("pthread_join()"); 107 if (pthread_join(tid_write_1, NULL) != 0) 108 err_exit("pthread_join()"); 109 if (pthread_join(tid_write_2, NULL) != 0) 110 err_exit("pthread_join()"); 111 112 return 0; 113 }
pthread中提供的锁有:pthread_mutex_t、pthread_spinlock_t、pthread_rwlock_t。
pthread_mutex_t是互斥锁,同一瞬间只能有一个线程能够获取锁,其他线程在等待获取锁的时候会进入休眠状态。因此pthread_mutex_t消耗的CPU资源很小,但是性能不高,因为会引起线程切换。
pthread_spinlock_t是自旋锁,同一瞬间也只能有一个线程能够获取锁,不同的是,其他线程在等待获取锁的过程中并不进入睡眠状态,而是在 CPU上进入“自旋”等待。自旋锁的性能很高,但是只适合对很小的代码段加锁(或短期持有的锁),自旋锁对CPU的占用相对较高。
pthread_rwlock_t是读写锁,同时可以有多个线程获得读锁,同时只允许有一个线程获得写锁。其他线程在等待锁的时候同样会进入睡眠。读写锁在互斥锁的基础上,允许多个线程“读”,在某些场景下能提高性能。
对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
https://blog.csdn.net/JCPGEE/java/article/details/79377948