mutex、读写锁、自旋锁、信号量以及RCU的性能测试

6/12/2022 知识

# mutex、读写锁、自旋锁、信号量以及RCU的性能测试

# 前言

本例为一个读线程和一个写线程,在不同加锁情况下测试一秒钟读写次数 没有测试多线程情况,结果只有参考意义 读写次数还与cpu频率相关 但大致不同种类的锁性能比较差距不大 测试源码和过程在最下面

# 一、直接上结论

# 1、以下为每秒读写次数

次数与cpu频率相关,不同机器测试结果不同(这里使用ubuntu20.04虚拟机测试的)

读写锁 21000k

mutex 31000k

自旋锁 58000k

信号量 27000k

rcu 47000k

# 2、锁的特点和使用场景

自旋锁特点 循环等待等 力度很小 用于链表头指针改变等情况

mutex 加锁时线程休眠一会看一下 可用于大部分情况

读写锁 读写都要判断 加锁复杂 不推荐使用

信号量 pv操作 比mutex低一点

rcu 读写锁变种 read copy update 可以代替读写锁情况

# 二、环境准备

编译命令
    gcc -o rcu rcu.c -lpthread -lurcu
1
rcu锁需要安装liburcu-dev
    apt-get install liburcu-dev
1

# 三、实际测试结果

不加锁

root@luo:~/workspace/test# ./rcu 
Error: x:2340421, y:3524383
1
2

读写锁

root@luo:~/workspace/test# ./rcu 
reads: 19500709, 19500 K reads/sec
reads: 44758029, 22379 K reads/sec
reads: 65393430, 21797 K reads/sec
reads: 85189522, 21297 K reads/sec

1
2
3
4
5
6

信号量

root@luo:~/workspace/test# ./rcu 
reads: 27627678, 27627 K reads/sec
reads: 55094966, 27547 K reads/sec
reads: 82395410, 27465 K reads/sec
reads: 109609817, 27402 K reads/sec
1
2
3
4
5

mutex

root@luo:~/workspace/test# ./rcu 
reads: 32018261, 32018 K reads/sec
reads: 63767452, 31883 K reads/sec
reads: 95838658, 31946 K reads/sec
reads: 127792109, 31948 K reads/sec

1
2
3
4
5
6

自旋锁

root@luo:~/workspace/test# ./rcu 
reads: 57844075, 57844 K reads/sec
reads: 117047083, 58523 K reads/sec
reads: 173215973, 57738 K reads/sec
reads: 229239811, 57309 K reads/sec

1
2
3
4
5
6

RCU

root@luo:~/workspace/test# ./rcu 
reads: 47511136, 47511 K reads/sec
reads: 94736084, 47368 K reads/sec
reads: 141648406, 47216 K reads/sec
reads: 188779939, 47194 K reads/sec

1
2
3
4
5
6

# 四、 源码

rcu.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <pthread.h>
#include <limits.h>
#include <semaphore.h>

#include <urcu.h>

struct point {
	int x;
	int y;
};

struct point *gp;
int done = 0;
long reads = 0;


pthread_rwlock_t rwlock;
pthread_mutex_t mutex;
pthread_spinlock_t spinlock;
sem_t sem;

void *timer(void *arg) {

	struct timespec ts, ts2;
	timespec_get(&ts, TIME_UTC);

	while (!done) {

		sleep(1);
		timespec_get(&ts2, TIME_UTC);

		time_t sec = ts2.tv_sec - ts.tv_sec;

		printf("reads: %ld, %ld K reads/sec\n", reads, (reads/sec)/1000);

	}

}

void *updater(void *arg) {

	struct point *p;
	struct point *old;

	int i = 0;
	for (i = 0;i < INT_MAX;i ++) {

		p = malloc(sizeof(struct point));

		p->x = i;
		p->y = i+1;

		old = gp;
#if 0
		gp = p;

#elif 0
		pthread_rwlock_wrlock(&rwlock);
		gp = p;
		pthread_rwlock_unlock(&rwlock);

#elif 0

		pthread_mutex_lock(&mutex);
		gp = p;
		pthread_mutex_unlock(&mutex);

#elif 0

		pthread_spin_lock(&spinlock);
		gp = p;
		pthread_spin_unlock(&spinlock);

#elif 1

		rcu_assign_pointer(gp, p);
		synchronize_rcu();

#else

		sem_wait(&sem);
		gp = p;
		sem_post(&sem);

#endif
		free(old);
		
	}

}

void *reader(void *arg) {

	rcu_register_thread(); //urcu

	while (!done) {

		int x, y;
#if 0
		x = gp->x;
		y = gp->y;
#elif 0
		pthread_rwlock_rdlock(&rwlock);
		x = gp->x;
		y = gp->y;
		pthread_rwlock_unlock(&rwlock);

#elif 0

		pthread_mutex_lock(&mutex);
		x = gp->x;
		y = gp->y;
		pthread_mutex_unlock(&mutex);

#elif 0

		pthread_spin_lock(&spinlock);
		x = gp->x;
		y = gp->y;
		pthread_spin_unlock(&spinlock);

#elif 1

		rcu_read_lock();

		struct point *p = rcu_dereference(gp);
		x = p->x;
		y = p->y;

		rcu_read_unlock();

#else

		sem_wait(&sem);
		x = gp->x;
		y = gp->y;
		sem_post(&sem);

#endif
		reads ++;

		if (y != x+1) {
			printf("Error: x:%d, y:%d\n", x, y);
			done = 1;
			break;
		}

	}

	rcu_unregister_thread();

	exit(1);
}


int main() {

	pthread_t tid[3];

	pthread_rwlock_init(&rwlock, NULL);
	pthread_mutex_init(&mutex, NULL);
	pthread_spin_init(&spinlock, PTHREAD_PROCESS_SHARED);
	sem_init(&sem, 0, 1);

	rcu_init(); // rcu 

	gp = malloc(sizeof(struct point));
	gp->x = 1;
	gp->y = 2;

	pthread_create(&tid[0], NULL, updater, NULL);
	pthread_create(&tid[1], NULL, reader, NULL);
	pthread_create(&tid[2], NULL, timer, NULL);

	int i = 0;
	for (i = 0;i < 3;i ++) {
		pthread_join(tid[i], NULL);
	}

	free(gp);
}


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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187