Mutex变量是非0即1的,可看作一种资源的可用数量,初始化时Mutex是1,表示有一个可用资源,加锁时获得该资源,将Mutex减到0,表示不再有可用资源,解锁时释放该资源,将Mutex重新加到1,表示又有了一个可用资源。信号量(Semaphore)和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1。
如下所示的代码示例用semaphore实现生产者-消费者模型
#include <stdlib.h> #include <pthread.h> #include <stdio.h> #include <semaphore.h> #define NUM 5 int queue[NUM]; sem_t blank_number, product_number; void *producer(void *arg) { int p = 0; while (1) { sem_wait(&blank_number); queue[p] = rand() % 1000 + 1; printf("Produce %d\n", queue[p]); sem_post(&product_number); p = (p+1)%NUM; sleep(rand()%5); } } void *consumer(void *arg) { int c = 0; while (1) { sem_wait(&product_number); printf("Consume %d\n", queue[c]); queue[c] = 0; sem_post(&blank_number); c = (c+1)%NUM; sleep(rand()%5); } } int main(int argc, char *argv[]) { pthread_t pid, cid; sem_init(&blank_number, 0, NUM); sem_init(&product_number, 0, 0); pthread_create(&pid, NULL, producer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_join(pid, NULL); pthread_join(cid, NULL); sem_destroy(&blank_number); sem_destroy(&product_number); return 0; }
semaphore可以用mutex和condition variable来实现,如下代码所示。
#include <stdlib.h> #include <pthread.h> #include <stdio.h> #include <semaphore.h> #define NUM 5 int queue[NUM]; sem_t blank_number, product_number; int prod_counter = 0; pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_cond_t cons_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; void *producer(void *arg) { int p = 0; while (1) { sem_wait(&blank_number); queue[p] = rand() % 1000 + 1; printf("Produce %d\n", queue[p]); sem_post(&product_number); p = (p+1)%NUM; sleep(rand()%5); } } void *consumer(void *arg) { int c = 0; while (1) { sem_wait(&product_number); printf("Consume %d\n", queue[c]); queue[c] = 0; sem_post(&blank_number); c = (c+1)%NUM; sleep(rand()%5); } } void *producer_cond(void *arg) { int p = 0; while (1) { //sem_wait(&blank_number); pthread_mutex_lock(&lock); if ((NUM - prod_counter) > 0) { prod_counter = (prod_counter + 1)%NUM; } else { printf("full products\n"); while ((NUM - prod_counter) == 0) { pthread_cond_wait(&cons_product, &lock); } prod_counter = (prod_counter + 1)%NUM; } queue[p] = rand() % 1000 + 1; printf("Cond_Produce %d\n", queue[p]); //sem_post(&product_number); pthread_mutex_unlock(&lock); pthread_cond_signal(&has_product); p = (p+1)%NUM; sleep(rand()%5); } } void *consumer_cond(void *arg) { int c = 0; while (1) { //sem_wait(&product_number); pthread_mutex_lock(&lock); if (prod_counter > 0) { prod_counter = (prod_counter - 1)%NUM; } else { printf("no products\n"); while (prod_counter == 0) { pthread_cond_wait(&has_product, &lock); } prod_counter = (prod_counter - 1)%NUM; } printf("Cond_Consume %d\n", queue[c]); queue[c] = 0; //sem_post(&blank_number); pthread_mutex_unlock(&lock); pthread_cond_signal(&cons_product); c = (c+1)%NUM; sleep(rand()%5); } } int main(int argc, char *argv[]) { /* pthread_t pid, cid; sem_init(&blank_number, 0, NUM); sem_init(&product_number, 0, 0); pthread_create(&pid, NULL, producer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_join(pid, NULL); pthread_join(cid, NULL); sem_destroy(&blank_number); sem_destroy(&product_number); */ pthread_t pid_con, cid_con; srand(time(NULL)); pthread_create(&pid_con, NULL, producer_cond, NULL); pthread_create(&cid_con, NULL, consumer_cond, NULL); pthread_join(pid_con, NULL); pthread_join(cid_con, NULL); return 0; }