Linux-线程:posix信号量实现生产者消费者模型

与sustem v的区别

之前我们学到过system v版本的进程间通信中也有syetem v版本的信号量,那么它与posix的信号量有什么区别呢?

一般来说System V版本的进程间通信用于进程,而POSIX版 本的进程间通信用于线程。他们的区别主要在于信号量和共享内存。

信号量的区别:
system v版本的信号量一般是随内核的,无论有无竞争都要执行系统调用,所以性能上比较差。它的接口是semget,semctl,semop。

posix版本的信号量同时支持无命名的信号量和有命名的信号量。它在无竞争的时候是不陷入内核的。所以效率更高。

  • 无命名的信号量一般用于线程同步,它的生命周期是随进程的,它的主要接口有 sem_init,sem_destory,sem_wait,sem_post。
  • 有命名的信号量一般用于进程同步,一般有一个文件关联他们,有命名的信号量是随内核的,它的主要接口有 sem_open,sem_close,sem_unlink。

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

倘若消费者的速度跟不上生产者,生产者生产多个消费者才取一个,就会造成以下情况,基于环形队列,就会造成对数据的覆盖。
Linux-线程:posix信号量实现生产者消费者模型_第1张图片
下面修改代码:

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

Linux-线程:posix信号量实现生产者消费者模型_第2张图片

现在可以看到,基于信号量实现,就不会出现消费者与生产者由于速度不匹配而出现的数据混乱现象。尽快生产者速度比消费者速度快,但是两者仍然能同步。

你可能感兴趣的:(Linux,Linux基础学习)