一、 互斥量
当多个线程共享一个变量时,一个线程读取这个变量的值,而有另外一个线程会修改这个变量的值,如果不加限制,就难以保证读取的变量值是修改之后还是修改之前的。为了保证变量不会被多个线程同时访问,引入互斥量,互斥量对共享数据的保护就像一把锁。
在pthreads中,任何时候仅有一个线程可以锁定互斥量,因此,当多个线程尝试去锁定互斥量时仅有一个会成功,直到锁定互斥量的线程解锁互斥量后,其他线程才可以去锁定。如此,线程就会轮流访问受保护数据。这就是互斥量的概念,在pthread中定义了一套用于线程同步的mutex函数。
#include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex); int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // pthread_mutex_destroy, pthread_mutex_init — destroy and initialize a mutex
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); // pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock — lock and unlock a mutex
二、 条件变量
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待“条件变量的条件成立”而挂起;另一个线程使“条件成立”(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥量结合在一起。
#include <pthread.h> 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; // pthread_cond_destroy, pthread_cond_init — destroy and initialize condition variables
#include <pthread.h> 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); // pthread_cond_timedwait, pthread_cond_wait — wait on a condition
#include <pthread.h> int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond); // pthread_cond_broadcast, pthread_cond_signal — broadcast or signal a condition
三、 生产者消费者问题
1、 示例代码
#include <stdio.h> #include <pthread.h> #define MAX_VALUE 2 #define MAX_COUNT 5 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t not_full = PTHREAD_COND_INITIALIZER; pthread_cond_t not_empty = PTHREAD_COND_INITIALIZER; int value = 0; void *producer(void *arg) { for(int i=0; i<MAX_COUNT; i++) { pthread_mutex_lock(&mutex); while(value == MAX_VALUE) { printf("Producer: waiting, full!\n"); pthread_cond_wait(¬_full, &mutex); } value++; printf("Producer: value == %d\n", value); pthread_cond_signal(¬_empty); pthread_mutex_unlock(&mutex); } return NULL; } void *consumer(void *arg) { for(int i=0; i<MAX_COUNT; i++) { pthread_mutex_lock(&mutex); while(value == 0) { printf("Consumer: waiting, empty!\n"); pthread_cond_wait(¬_empty, &mutex); } printf("Consumer: value == %d\n", value); value--; pthread_cond_signal(¬_full); pthread_mutex_unlock(&mutex); } return NULL; } int main(void) { pthread_t t1, t2, t3, t4; pthread_create(&t1, NULL, producer, NULL); pthread_create(&t2, NULL, producer, NULL); pthread_create(&t3, NULL, consumer, NULL); pthread_create(&t4, NULL, consumer, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_join(t3, NULL); pthread_join(t4, NULL); return 0; }
2、 运行结果
[ycxie@fedora Workspace]$ gcc mutex_cond.c -o mutex_cond -pthread -Wall [ycxie@fedora Workspace]$ ./mutex_cond Producer: value == 1 Producer: value == 2 Producer: waiting, full! Consumer: value == 2 Consumer: value == 1 Consumer: waiting, empty! Consumer: waiting, empty! Producer: value == 1 Producer: value == 2 Consumer: value == 2 Consumer: value == 1 Consumer: waiting, empty! Consumer: waiting, empty! Producer: value == 1 Producer: value == 2 Producer: waiting, full! Consumer: value == 2 Consumer: value == 1 Consumer: waiting, empty! Consumer: waiting, empty! Producer: value == 1 Producer: value == 2 Producer: waiting, full! Producer: waiting, full! Consumer: value == 2 Producer: value == 2 Consumer: value == 2 Consumer: value == 1 Consumer: waiting, empty! Producer: value == 1 Consumer: value == 1