1、读写锁
互斥锁:试图进入临界区的所有其他进程都阻塞住。
读写锁:获取读写锁用于读和获取读写锁用于写作区分。
读写锁分配规则:
(1)、读锁:共享锁,此时可以有多个读锁,但是没有写锁。
(2)、写锁:独占锁,此时在也没有任何的写/读锁。
(3)、读写锁中,写锁优先抢占资源。
2、编程实现
需要使用:pthread_rwlock_t rwlock //定义了一个读写锁变量;
使用的API为:
函数 | 说明 |
pthread_rwlock_wrlock() | 写锁 |
pthread_rwlock_rdlock() | 读锁 |
pthread_rwlock_unlock() | 解锁 |
代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
pthread_rwlock_t rwlock;
void
* fun1(
void
*arg){
pthread_rwlock_wrlock(&rwlock);
printf
(
"This is fun1, wlock\n"
);
sleep(2);
pthread_rwlock_unlock(&rwlock);
}
void
* fun2(
void
*arg){
pthread_rwlock_rdlock(&rwlock);
printf
(
"This is fun2, rlock\n"
);
pthread_rwlock_unlock(&rwlock);
}
void
* fun3(
void
*arg){
pthread_rwlock_wrlock(&rwlock);
printf
(
"This is fun3, wlock\n"
);
pthread_rwlock_unlock(&rwlock);
}
int
main(
void
){
pthread_t tid1, tid2[5], tid3[5];
pthread_create(&tid1, NULL, fun1, NULL);
sleep(1);
int
i;
for
(i = 0; i < 5; i++){
pthread_create(&tid2[i], NULL, fun2, NULL);
//读锁
}
for
(i = 0; i < 5; i++){
pthread_create(&tid3[i], NULL, fun3, NULL);
//写锁
}
pthread_join(tid1, NULL);
for
(i = 0; i < 5; i++){
pthread_join(tid2[i], NULL);
pthread_join(tid3[i], NULL);
}
return
0;
}
|
运行结果
3、实现写锁优先
因为系统内部是写锁优先,经查看源码,现在实现此功能;以下是要实现的.c文件。
代码如下:
(1)、utili.h
1
2
3
|
#include<unistd.h>
#include<stdio.h>
#include<pthread.h>
|
(2)、pthread_rwlock.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#ifndef _PTHREAD_RWLOCK_H
#define _PTHREAD_RWLOCK_H
#include"utili.h"
enum
{EINVAL, EBUSY};
typedef
struct
{
pthread_mutex_t rw_mutex;
pthread_cond_t rw_condreaders;
pthread_cond_t rw_condwriters;
int
rw_magic;
int
rw_nwaitreaders;
int
rw_nwaitwriters;
int
rw_refcount;
//<0 ==0 >0
}my_pthread_rwlock_t;
#define RW_MAGIC 0x2016911
#define MY_PTHREAD_RWLOCK_INITIALIZER {PTHREAD_MUTEX_INITIALIZER, \
PTHREAD_COND_INITIALIZER, \
PTHREAD_COND_INITIALIZER, \
RW_MAGIC, \
0, 0, 0}
typedef
int
my_pthread_rwlockattr_t;
int
my_pthread_rwlock_init(my_pthread_rwlock_t *rw, my_pthread_rwlockattr_t *at);
int
my_pthread_rwlock_destroy(my_pthread_rwlock_t *rw);
int
my_pthread_rwlock_rdlock(my_pthread_rwlock_t *rw);
int
my_pthread_rwlock_wrlock(my_pthread_rwlock_t *rw);
int
my_pthread_rwlock_unlock(my_pthread_rwlock_t *rw);
int
my_pthread_rwlock_tryrdlock(my_pthread_rwlock_t *rw);
int
my_pthread_rwlock_trywrlock(my_pthread_rwlock_t *rw);
#endif
|
(3)、pthread_rwlock_init.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include"pthread_rwlock.h"
int
my_pthread_rwlock_init(my_pthread_rwlock_t *rw, my_pthread_rwlockattr_t *at){
int
result;
if
(at != NULL)
return
EINVAL;
if
((result = pthread_mutex_init(&rw->rw_mutex, NULL)) != 0)
goto
err1;
if
((result = pthread_cond_init(&rw->rw_condreaders, NULL)) != 0)
goto
err2;
if
((result = pthread_cond_init(&rw->rw_condwriters, NULL)) != 0)
goto
err3;
rw->rw_nwaitreaders = 0;
rw->rw_nwaitwriters = 0;
rw->rw_refcount = 0;
rw->rw_magic = RW_MAGIC;
return
0;
err3:
pthread_cond_destroy(&rw->rw_condreaders);
err2:
pthread_mutex_destroy(&rw->rw_mutex);
err1:
return
result;
}
|
(4)、pthread_rwlock_wrlock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include"pthread_rwlock.h"
int
my_pthread_rwlock_wrlock(my_pthread_rwlock_t *rw){
int
result;
if
(rw->rw_magic != RW_MAGIC){
return
EINVAL;
}
if
((result = pthread_mutex_lock(&rw->rw_mutex)) != 0){
return
result;
}
while
(rw->rw_refcount != 0){
rw->rw_nwaitwriters++;
result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);
rw->rw_nwaitwriters--;
if
(result != 0)
break
;
}
if
(result == 0){
rw->rw_refcount = -1;
}
pthread_mutex_unlock(&rw->rw_mutex);
return
result;
}
|
(5)、pthread_rwlock_rdlock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include"pthread_rwlock.h"
int
my_pthread_rwlock_rdlock(my_pthread_rwlock_t *rw){
int
result;
if
(rw->rw_magic != RW_MAGIC)
return
EINVAL;
if
((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
return
result;
while
(rw->rw_refcount<0 || rw->rw_nwaitwriters>0){
rw->rw_nwaitreaders++;
result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);
rw->rw_nwaitreaders--;
if
(result != 0)
break
;
}
if
(result == 0){
rw->rw_refcount++;
}
pthread_mutex_unlock(&rw->rw_mutex);
return
result;
}
|
(6)、pthread_rwlock_unlock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include"pthread_rwlock.h"
int
my_pthread_rwlock_unlock(my_pthread_rwlock_t *rw){
int
result;
if
(rw->rw_magic != RW_MAGIC)
return
EINVAL;
if
((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
return
result;
if
(rw->rw_refcount > 0){
rw->rw_refcount--;
}
else
if
(rw->rw_refcount == -1){
rw->rw_refcount = 0;
}
else
{
printf
(
"refcount error.\n"
);
}
if
(rw->rw_nwaitwriters > 0){
if
(rw->rw_refcount == 0)
result = pthread_cond_signal(&rw->rw_condwriters);
}
else
if
(rw->rw_nwaitreaders > 0){
result = pthread_cond_broadcast(&rw->rw_condreaders);
}
pthread_mutex_unlock(&rw->rw_mutex);
return
result;
}
|
(7)、pthread_rwlock_destroy.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include"pthread_rwlock.h"
int
my_pthread_rwlock_destroy(my_pthread_rwlock_t *rw)
{
if
(rw->rw_magic != RW_MAGIC)
return
EINVAL;
if
(rw->rw_refcount!=0 || rw->rw_nwaitreaders!=0 || rw->rw_nwaitwriters!=0)
return
EBUSY;
pthread_mutex_destroy(&rw->rw_mutex);
pthread_cond_destroy(&rw->rw_condreaders);
pthread_cond_destroy(&rw->rw_condwriters);
rw->rw_magic = 0;
return
0;
}
|
(8)、test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#include"utili.h"
#include"pthread_rwlock.h"
my_pthread_rwlock_t rwlock = MY_PTHREAD_RWLOCK_INITIALIZER;
void
* fun1(
void
*arg){
my_pthread_rwlock_wrlock(&rwlock);
printf
(
"This is fun1. wrlock\n"
);
sleep(5);
printf
(
"fun1 wake up.\n"
);
my_pthread_rwlock_unlock(&rwlock);
}
void
* fun2(
void
*arg){
my_pthread_rwlock_rdlock(&rwlock);
printf
(
"This is fun2.rdlock.\n"
);
my_pthread_rwlock_unlock(&rwlock);
}
void
* fun3(
void
*arg){
my_pthread_rwlock_wrlock(&rwlock);
printf
(
"This is fun3,wrlock.\n"
);
my_pthread_rwlock_unlock(&rwlock);
}
int
main(){
pthread_t tid1, tid2[5],tid3[5];
int
i;
pthread_create(&tid1, NULL, fun1, NULL);
sleep(1);
for
(i=0; i<5; ++i){
pthread_create(&tid2[i], NULL, fun2, NULL);
}
for
(i=0; i<5; ++i){
pthread_create(&tid3[i], NULL, fun3, NULL);
}
pthread_join(tid1, NULL);
for
(i=0; i<5; ++i){
pthread_join(tid2[i], NULL);
pthread_join(tid3[i], NULL);
}
return
0;
}
|
(9)、Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
OBJ=test.o pthread_rwlock_rdlock.o pthread_rwlock_unlock.o pthread_rwlock_wrlock.o pthread_rwlock_init
.o
SRC=test.c pthread_rwlock_rdlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c pthread_rwlock_init
.c
test:$(OBJ)
gcc -o test $(OBJ) -lpthread
test.o:test.c
gcc -o test.o -c test.c
pthread_rwlock_rdlock.o:pthread_rwlock_rdlock.c
gcc -o pthread_rwlock_rdlock.o -c pthread_rwlock_rdlock.c
pthread_rwlock_unlock.o:pthread_rwlock_unlock.c
gcc -o pthread_rwlock_unlock.o -c pthread_rwlock_unlock.c
pthread_rwlock_wrlock.o:pthread_rwlock_wrlock.c
gcc -o pthread_rwlock_wrlock.o -c pthread_rwlock_wrlock.c
pthread_rwlock_init.o:pthread_rwlock_init.c
gcc -o pthread_rwlock_init.o -c pthread_rwlock_init.c
.PHONY:clean
clean:
rm *.o test
|
运行结果:
这样我们自己就实现了写锁优先了,根据其原理,我们就可以改写为读锁优先。