POSIX 信号量与互斥锁

介绍POSIX 信号量与互斥锁的用法,以及自旋锁和读写锁的介绍,解决生产者与消费者问题。

POSIX信号量相关函数

1
2
3
4
5
6
7
8
9
10
11
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_post(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

POSIX互斥锁相关函数

1
2
3
4
5
6
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

生产者和消费者问题

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
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
#define CONSUMERS_COUNT 5
#define PRODUCERS_COUNT 5
#define BUFFSIZE 10
int g_buffer[BUFFSIZE];
unsigned short in = 0;
unsigned short out = 0;
unsigned short produce_id = 0;
unsigned short consume_id = 0;
sem_t g_sem_full;
sem_t g_sem_empty;
pthread_mutex_t g_mutex;
pthread_t g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT];
void *consume(void *arg) {
int num = (int)arg;
while (1) {
printf("%d wait buffer not empty\n", num);
sem_wait(&g_sem_empty);
pthread_mutex_lock(&g_mutex);
int i;
for (i=0; i<BUFFSIZE; ++i) {
printf("%02d ", i);
if (g_buffer[i] == -1) {
printf("%s", "null");
} else {
printf("%d", g_buffer[i]);
}
if (i == out) {
printf("\t<--consume");
}
printf("\n");
}
consume_id = g_buffer[out];
printf("%d start consume product %d\n", num, consume_id);
g_buffer[out] = -1;
out = (out + 1) % BUFFSIZE;
printf("%d end consume product %d\n", num, consume_id);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_full);
sleep(1);
}
return NULL;
}
void *produce(void *arg) {
int num = (int)arg;
while (1) {
printf("%d wait buffer not full\n", num);
sem_wait(&g_sem_full);
pthread_mutex_lock(&g_mutex);
int i;
for (i=0; i<BUFFSIZE; ++i) {
printf("%02d ", i);
if (g_buffer[i] == -1) {
printf("%s", "null");
} else {
printf("%d", g_buffer[i]);
}
if (i == in) {
printf("\t<--produce");
}
printf("\n");
}
printf("%d start produce product %d\n", num, produce_id);
g_buffer[in] = produce_id;
in = (in + 1) % BUFFSIZE;
printf("%d end produce product %d\n", num, produce_id++);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem_empty);
sleep(1);
}
return NULL;
}
int main() {
sem_init(&g_sem_full, 0, BUFFSIZE);
sem_init(&g_sem_empty, 0, 0);
pthread_mutex_init(&g_mutex, NULL);
int i;
for (i=0; i<BUFFSIZE; ++i) {
g_buffer[i] = -1;
}
for (i=0; i<CONSUMERS_COUNT; ++i) {
pthread_create(&g_thread[i], NULL, consume, (void *)i);
}
for (i=0; i<PRODUCERS_COUNT; ++i) {
pthread_create(&g_thread[i+CONSUMERS_COUNT], NULL, produce, (void *)i);
}
for (i=0; i<CONSUMERS_COUNT+PRODUCERS_COUNT; ++i) {
pthread_join(g_thread[i], NULL);
}
sem_destroy(&g_sem_full);
sem_destroy(&g_sem_empty);
pthread_mutex_destroy(&g_mutex);
return 0;
}

自旋锁

  • 自旋锁类似于互斥锁,它的性能比互斥锁更高。
  • 自旋锁与互斥锁很重要的区别在于,线程在申请自旋锁的时候,线程不会被挂起,它处于忙等待的状态。
    1
    2
    3
    4
    5
    int pthread_spin_destroy(pthread_spinlock_t *lock);
    int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
    int pthread_spin_lock(pthread_spinlock_t *lock);
    int pthread_spin_trylock(pthread_spinlock_t *lock);
    int pthread_spin_unlock(pthread_spinlock_t *lock);

读写锁

  • 只要没有线程持有给定的读写锁用于写,那么任意数目的线程可以持有读写锁用于读
  • 仅当没有线程持有某个给定的读写锁用于读或者写时,才能分配读写锁用于写
  • 读写锁用于读成为共享锁,读写锁用于写成为排他锁
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);