作者:菜菜ING | 来源:互联网 | 2023-09-23 16:56
一、读写锁基本概念读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区,读写锁比它有更高的并行性。读写锁有以下特点:1、如果一个线程用读锁锁定了临
一、读写锁基本概念
读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区,读写锁比它有更高的并行性。
读写锁有以下特点:
1、如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿!
2、如果一个线程用写锁锁住了临界区,那么其他线程不管是读锁还是写锁都会发生阻塞!
简单讲,读写锁应该满足以下三种关系:
1、读-写,排他
2、写-写,排他
3、读-读,共享
二、相关函数接口
1、创建读写锁
主要有两种方法:
(1)宏常量初始化
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
(2)函数初始化
函数原型:
函数说明:
参数:
rwlock:读写锁的pthread_rwlock_t结构指针
attr:读写锁的属性结构指针。不需要别的属性默认为NULL。
返回值:成功返回0,失败返回错误码。
2、读写锁销毁:
int pthread_rwclock_dsestroy(pthread_rwlock_t *rwlock);
成功返回0,失败返回错误码。
3、加锁和解锁:
这几个函数都是成功返回0,失败返回错误码。
try类函数加锁:如果获取不到锁,会立即返回错误EBUSY。
三、举例验证读写锁
创建三个读者线程,两个写者线程,并仔仔观察这五个线程进入临界区的先后顺序:
1 #include
2 #include
3 #include
4 #include
5
6 int counter;
7 pthread_rwlock_t rwlock;
8
9 void *Write(void*arg)
10 {
11 int t;
12 int i=*(int*)arg;
13 free(arg);
14
15 while(1)
16 {
17 t=counter;
18 usleep(100000);
19
20 pthread_rwlock_wrlock(&rwlock);
21 printf("Write:%d :%#x:counter=%d ++counter=%d\n",i,pthread_self(),t,++counter);
22 pthread_rwlock_unlock(&rwlock);
23 usleep(500000);
24 }
25 }
26
27 void * Read(void*arg)
28 {
29 int t;
30 int i=*(int*)arg;
31 free(arg);
32 while(1)
33 {
34 pthread_rwlock_rdlock(&rwlock);
35 printf("Read:%d:%#x:counter=%d\n",i,pthread_self(),counter);
36 pthread_rwlock_unlock(&rwlock);
37 usleep(90000);
38 }
40
41 int main()
42 {
43 int i=0;
44 pthread_t tid[5];
45 pthread_rwlock_init(&rwlock,NULL);
46 for(i=0;i<3;i++)
47 {
48 int *p=(int*)malloc(sizeof(int));
49 *p=i;
50 pthread_create(&tid[i],NULL,Read,(void*)p);
51 }
52 for(i=3;i<5;i++)
53 {
54 int *p=(int*)malloc(sizeof(int));
55 *p=i;
56 pthread_create(&tid[i],NULL,Write,(void*)p);
57 }
58 for( i=0;i<5;i++)
59 {
60 pthread_join(tid[i],NULL);
61 }
62 pthread_rwlock_destroy(&rwlock);
63 }
运行结果:
通过运行结果可以看出,读锁请求可以同时进行,其counter值相等,读锁可以一起进入临界区,而写锁在临界区里面停留时都不会有其他线程能进来!因为写锁请求会阻塞后面的读锁,2个写锁一起请求会让读锁饥饿。