信号量实现生产者-消费者模型


前言

信号量广泛用于进程或线程间的同步和互斥,本质上是一个非负整数计数器。当信号量值大于 0 时,则可以访问公共资源,否则将阻塞访问
PV 是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1
在这里插入图片描述
信号量一般分为两种:
1:无名信号量,一般用于线程间和父子进程间同步或互斥,保存在内存中
2:有名信号量,一般用于普通进程间同步或互斥,创建一个文件保存在文件中
本文将以无名信号量来实现生产者消费者模型

一、无名信号量常用函数

 1. int sem_init(sem_t *sem, int pshared, unsigned int value);
        // 创建信号量
        // pshared:控制信号量的类型,0 表示线程间共享,其它表示进程间共享
	    // value:信号量的初始值
 3. int sem_post(sem_t *sem);
        // 以原子操作的方式给信号量的值加1(V操作),并唤醒调用 sem_wait 处于等待信号量状态的线程
 4. int sem_wait(sem_t *sem);
        // 以原子操作的方式给信号量的值减1(P操作),如果信号量值为 0 则等待,直到有线程调用 sem_post 增加了该信号量的值
 5. int sem_trywait(sem_t *sem);
 		// 非阻塞方式,如果信号量的值为 0 则立即返回,返回错误 EAGAIN
 6. int sem_getvalue(sem_t *sem, int *sval);
  	    // 获取信号量的值,保存在 sval 中
 7. int sem_destory(sem_t *sem);
 		// 销毁信号量,释放调用 sem_init 申请的资源

二、生产者-消费者模型代码

有一个长度为 N 的缓冲池为生产者和消费者所共有。只要缓冲池未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。生产者往缓冲池放信息的时候,消费者不可操作缓冲池,反之亦然

代码实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define BUFF_SIZE 5      // 缓冲池大小
char count = 0;          // 缓冲池中消息的数目
pthread_mutex_t mutex;   // 互斥量,用于生产者和消费者互斥操作缓冲池
sem_t semCanCustom;      // 消费者信号量,不为 0 时表示消费者可以消费资源
sem_t semCanProduct;     // 生产者信号量,不为 0 时表示生产者可以生产资源

void* thread_producer(void* arg)
{
    while (1)
    {
        sem_wait(&semCanProduct);	// 等待缓冲池不满
        pthread_mutex_lock(&mutex);
        count++;
        printf("count %d producer\n", count);
        pthread_mutex_unlock(&mutex);
        sem_post(&semCanCustom);    // 告知消费者线程可以消费了
        sleep(0.5);
    }
}

void* thread_consumer(void* arg)
{
    while (1)
    {
        sem_wait(&semCanCustom);    // 等待缓冲池不空
        pthread_mutex_lock(&mutex);
        count--;
        printf("count %d consumer\n", count);
        pthread_mutex_unlock(&mutex);
        sem_post(&semCanProduct);   // 告知生产者线程可以生产了
        sleep(0.5);
    }
}

int main()
{
    pthread_t ptid, ctid;

    pthread_mutex_init(&mutex, NULL);
    sem_init(&semCanCustom, 0, 0);           // 消费者信号量初始值为 0,表示初始不能消费
    sem_init(&semCanProduct, 0, BUFF_SIZE);  // 生产者信号量初始值为缓冲池大小,表示初始可以生产 N 个资源
    pthread_create(&ptid, NULL, thread_producer, NULL);
    pthread_create(&ctid, NULL, thread_consumer, NULL);
    pthread_join(ptid, NULL);
    pthread_join(ctid, NULL);
    pthread_mutex_destroy(&mutex);
    sem_destroy(&semCanCustom);
    sem_destroy(&semCanProduct);
    return 0;
}
  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值