之前我们学到过system v版本的进程间通信中也有syetem v版本的信号量,那么它与posix的信号量有什么区别呢?
一般来说System V版本的进程间通信用于进程,而POSIX版 本的进程间通信用于线程。他们的区别主要在于信号量和共享内存。
信号量的区别:
system v版本的信号量一般是随内核的,无论有无竞争都要执行系统调用,所以性能上比较差。它的接口是semget,semctl,semop。
posix版本的信号量同时支持无命名的信号量和有命名的信号量。它在无竞争的时候是不陷入内核的。所以效率更高。
下面来详细说说用于线程同步的posix信号量。
介绍接口:
初始化信号量:
int sem_init(sem_t *sem, int pshared, unsigned int value);
销毁信号量:
int sem_destroy(sem_t *sem);
等待信号量
int sem_wait(sem_t *sem);
发布信号量:
int sem_post(sem_t *sem);
下面编写代码:使用信号量实现生产者消费者模型。基于固定大小的环形队列。
我们先来实现无信号量的版本,看看是什么效果。
pthread_mutex_t mutex;
void* consumers(void* arg)
{
SeqQueue*q=(SeqQueue* )arg;
char top;
while(1)
{
sleep(1);
pthread_mutex_lock(&mutex);
int ret=SeqQueueTop(q,&top);
SeqQueuePop(q);
if(ret==0)
{
printf("consumers can not get data!\n");
pthread_mutex_unlock(&mutex);
}
else
{
printf("consumer get data:%c\n",top);
pthread_mutex_unlock(&mutex);
}
}
}
void* produsers(void* arg)
{
SeqQueue* q=(SeqQueue*)arg;
char i='a';
while(1)
{
usleep(100000);
pthread_mutex_lock(&mutex);
SeqQueuePush(q,i);
printf("produsers set data:%c\n",i);
pthread_mutex_unlock(&mutex);
i++;
}
}
int main()
{
pthread_t id1,id2;
pthread_mutex_init(&mutex,NULL);
SeqQueue q;
SeqQueueInit(&q);
pthread_create(&id1,NULL,consumers,(void**)&q);
pthread_create(&id2,NULL,produsers,(void**)&q);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
倘若消费者的速度跟不上生产者,生产者生产多个消费者才取一个,就会造成以下情况,基于环形队列,就会造成对数据的覆盖。
下面修改代码:
pthread_mutex_t mutex;
sem_t p;
sem_t c;
void* consumers(void* arg)
{
SeqQueue*q=(SeqQueue* )arg;
char top;
while(1)
{
sleep(1);
sem_wait(&c);
pthread_mutex_lock(&mutex);
int ret=SeqQueueTop(q,&top);
SeqQueuePop(q);
if(ret==0)
{
printf("consumers can not get data!\n");
pthread_mutex_unlock(&mutex);
sem_post(&p);
}
else
{
printf("consumer get data:%c\n",top);
pthread_mutex_unlock(&mutex);
sem_post(&p);
}
}
}
void* produsers(void* arg)
{
SeqQueue* q=(SeqQueue*)arg;
char i='a';
while(1)
{
usleep(100000);
sem_wait(&p);
pthread_mutex_lock(&mutex);
SeqQueuePush(q,i);
printf("produsers set data:%c\n",i);
pthread_mutex_unlock(&mutex);
sem_post(&c);
i++;
}
}
int main()
{
pthread_t id1,id2;
pthread_mutex_init(&mutex,NULL);
sem_init(&c,0,0);
sem_init(&p,0,1);
SeqQueue q;
SeqQueueInit(&q);
pthread_create(&id1,NULL,consumers,(void**)&q);
pthread_create(&id2,NULL,produsers,(void**)&q);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_mutex_destroy(&mutex);
sem_destroy(&c);
sem_destroy(&p);
return 0;
}
现在可以看到,基于信号量实现,就不会出现消费者与生产者由于速度不匹配而出现的数据混乱现象。尽快生产者速度比消费者速度快,但是两者仍然能同步。