mutex实现semaphore


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;
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s