POSIX 条件变量

POSIX 条件变量的介绍,以及使用方法和使用规范,使用条件变量解决生产者与消费者的问题。


条件变量

  • 当一个线程互斥的访问某个变量时,他可能发现在其他线程改变状态之前,它什么也做不了。
  • 例如一个线程访问队列时,发现队列为空,它只能等待,直到其他线程将一个节点添加到队列中,这种情况就需要使用到条件变量。

条件变量函数

1
2
3
4
5
6
7
8
9
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

条件变量使用规范

  • 等待条件代码

    1
    2
    3
    4
    5
    pthread_mutex_lock(&mutex);
    while (条件为假)
    pthread_cond_wait(cond, mutex);
    修改条件
    pthread_mutex_unlock(&mutex);
  • 给条件发送信号代码

    1
    2
    3
    4
    pthread_mutex_lock(&mutex);
    设置条件为真
    pthread_cond_signal(cond);
    pthread_mutex_unlock(&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
#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
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
pthread_t g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT];
int nready = 0;
void *consume(void *arg) {
int num = (int)arg;
while (1) {
pthread_mutex_lock(&g_mutex);
while (nready == 0) {
printf("%d start wait a condition\n", num);
pthread_cond_wait(&g_cond, &g_mutex);
}
printf("%d end wait a condition\n", num);
printf("%d start consume product\n", num);
--nready;
printf("%d end consume product\n", num);
pthread_mutex_unlock(&g_mutex);
sleep(1);
}
return NULL;
}
void *produce(void *arg) {
int num = (int)arg;
while (1) {
pthread_mutex_lock(&g_mutex);
printf("%d start produce product\n", num);
++nready;
printf("%d end produce product\n", num);
pthread_cond_signal(&g_cond);
printf("%d signal\n", num);
pthread_mutex_unlock(&g_mutex);
sleep(1);
}
return NULL;
}
int main() {
pthread_cond_init(&g_cond, NULL);
pthread_mutex_init(&g_mutex, NULL);
int i;
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);
}
pthread_cond_destroy(&g_cond);
pthread_mutex_destroy(&g_mutex);
return 0;
}