用条件变量(Condition Variable)实现信号量(Semaphore),
主要是通过条件变量控制资源数的加减操作,在这里定义sem_t 为
struct sem{
int num;
pthread_mutex_t lock;
pthread_cond_t cond;
};
资源数由num决定,当num为0时应用条件变量让线程挂起,直到条件满足之后再次获取资源。
void sem_init(sem_t * semm, int num) 初始化函数,定义资源数。
void sem_wait(sem_t * semm) 获取资源,获得资源后,资源数-1,未获得资源则挂起等待,
这里需要注意的一点是,pthread_cond_wait在挂起等待的时候是不会占用互斥锁(mutex),
进而能保证sem_post对num的操作不被挂起。
void sem_post(sem_t * semm) 释放资源,资源数+1;
代码如下:
//"semaphore_xx.h"
#ifndef SEMAPHORE_XX_20121008
#define SEMAPHORE_XX_20121008
#include
#include
#include
#include
#include
#include
namespace sem_xx{
struct sem{
int num;
pthread_mutex_t lock;
pthread_cond_t cond;
};
typedef struct sem sem_t;
void sem_init(sem_t * semm, int num){
semm->num = num;
pthread_mutex_init(&(semm->lock), NULL);
pthread_cond_init(&(semm->cond), NULL);
}
void sem_wait(sem_t * semm){
pthread_mutex_lock(&(semm->lock));
while ( semm->num == 0)
pthread_cond_wait(&(semm->cond), &(semm->lock));
semm->num--;
pthread_mutex_unlock(&(semm->lock));
}
void sem_post(sem_t * semm){
pthread_mutex_lock(&(semm->lock));
/*fuck! Here is a stupid mistake!Just add the num will be ok!!
Otherwise,we will be blocked here!
while ( semm->num == 0)
pthread_cond_wait(&(semm->cond), &(semm->lock));
*/
semm->num++;
pthread_mutex_unlock(&(semm->lock));
pthread_cond_signal(&(semm->cond));
}
}
#endif
利用上面代码实现生产者-消费者模式:
代码如下:
//"test.cpp"
#include
#include
#include
#include
#include
#include
#include
//#include
#include "semaphore_xx.h"
#define NUM 5
int queue[NUM];
using namespace sem_xx;
sem 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, NUM);
sem_init(&product_number, 0);
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
return 0;
}