基于POSIX信号量实现生产者消费模型

一.基础知识

1.1 system V版本的信号量和POSIX下信号量的区别

我们前面讲过进程间通信有三种形式:管道、消息队列、信号量。这个信号量是system V版本下,以信号量集形式申请存在的,它标识着一个临界资源的有无从而控制不同的进程能否访问到该临界资源。但,现在,我们要讲的信号量是基于POSIX下的信号量,它用来标识资源的个数。

1.2 互斥锁和信号量

上篇所述,互斥锁(Mutex)可看作是某种资源的可用数,Mutex变量是非0即1的,初始化时Mutex为1,表示有一个可用资源;加锁时获得该资源,将Mutex减到0,表示不再有可用资源;解锁时释放该资源,将Mutex重新加到1,表示又有了一个可用资源。

即,信号量和Mutex作用类似,表示可用资源的数量,和Mutex不同的是信号量的数量可以大于1。

如果信号量描述的资源数目是1时,此时的信号量就和互斥锁相同!

这种信号量不仅可用于同一进程的线程间同步,也可用于不同进程间的同步。

二.相关函数

2.1初始化

semaphore变量的类型为sem_t,sem_init()初始化一个semaphore变量,

pshared:参数为0表示信号量用于同一进程的线程间同步

value:可用资源的数量

2.2 释放资源

2.3 P、V操作

sem_wait():获得资源(P操作-1),使semaphore的值减1,如果调用sem_wait()时semaphore的值已经是0,则挂起等待。如果不希望挂起等待,可以调用sem_trywait() 。

sem_post():释放资源(V操作+1),使semaphore 的值加1,同时唤醒挂起等待的线程。

三. 相关代码(多生产者多消费者模型)

//test.c  
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<pthread.h>
  4 #include<semaphore.h>
  5 
  6 #define MAX 20
  7 static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
  8 sem_t blank;
  9 sem_t data;
 10 
 11 int buf[MAX];
 12 
 13 void* product(void* arg)
 14 {
 15     int i=0;
 16     int index=0;
 17     while(1)
 18     {
 19         sem_wait(&blank);
 20         pthread_mutex_lock(&lock);
 21         buf[index++]=i++;
 22         index%=MAX;
 23         printf("product%d done...val is :%d\n",(int)arg,i-1);
 24         sem_post(&data);
 25         pthread_mutex_unlock(&lock);
 26         sleep(2);
 27     }
 28 }
 29 void* consumer(void* arg)
 30 {
 31     int index=0;
 32     while(1)
 33     {
 34         sem_wait(&data);
 35         pthread_mutex_lock(&lock);
 36         int val=buf[index++];
 37         index%=MAX;
 38         printf("consumer%d done...val is:%d\n",(int)arg,val);
 39         sem_post(&blank);
 40         pthread_mutex_unlock(&lock);
 41         sleep(1);
 42     }
 43 }
 44 int main()
 45 {
 46     sem_init(&blank,0,MAX);
 47     sem_init(&data,0,0);
 48 
 49     pthread_t product1;
 50     pthread_t product2;
 51     pthread_t product3;
 52     pthread_t consumer1;
 53     pthread_t consumer2;
 54     pthread_t consumer3;
 55 
 56     pthread_create(&product1,NULL,product,(void*)1);
 57     pthread_create(&product2,NULL,product,(void*)2);
 58     pthread_create(&product3,NULL,product,(void*)3);
 59     pthread_create(&consumer1,NULL,consumer,(void*)1);
 60     pthread_create(&consumer2,NULL,consumer,(void*)2);
 61     pthread_create(&consumer3,NULL,consumer,(void*)3);
 62 
 63     pthread_join(product1,NULL);
 64     pthread_join(product2,NULL);
 65     pthread_join(product3,NULL);
 66     pthread_join(consumer1,NULL);
 67     pthread_join(consumer2,NULL);
 68     pthread_join(consumer3,NULL);
 69 
 70     sem_destroy(&blank);
 71     sem_destroy(&data);
 72 
 73     pthread_mutex_destroy(&lock);
 74     
 75     return 0;
 76 }
 
 //makefile
   1 test:test.c
  2     gcc -o [email protected] $^ -lpthread
  3 .PHONY:clean
  4 clean:
  5     rm -f test

输出结果:

四.分析与总结

1)单生产但消费者模型,因为P、V操作已经让两者有序,相当于完成了同步与互斥(上述代码实现中去掉加锁解锁即第20,25,35,40行);多生产者多消费者模型,即上述代码实现。(因为消费者和消费者之间存在互斥问题,生产者和生产者之间也存在互斥问题)

2)加锁解锁的方式还有一种,即加在sem_wait之前,但这样可能会造成死锁问题:若消费者先进入,申请data,而此时产生data的生产者被挂起等待。

时间: 2024-10-21 03:06:50

基于POSIX信号量实现生产者消费模型的相关文章

基于POSIX的信号量的生产者消费者模型

信号量和Mutex类似,表示可用资源的数量,和Mutex不同的是,这个数量可以大于1,即如果信号量描述的资源数目是1时,此时的信号量和互斥锁相同. 下面我们看看POSIX semaphore库函数,它既可以用于同一进程的线程间同步,也可以用于不同进程间的同步. 1. int sem_init(sem_t *sem,int pshared,unsigned int value) 我们可以用此函数来创建一个未命名的信号量,pshared参数表明是否在多个进程中使用信号量,如果是,将其设置为非0 值,

并发编程【四】锁和队列及生产者消费模型

1.锁multiprocessing-Lock 锁的应用场景:当多个进程需要操作同一个文件/数据的时候: 当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题. 为保证数据的安全性,多进程中只有去操作一些进程之间可以共享的数据资源的时候才需要进行加锁: 枷锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务进行修改,即串行的修改,没错速度式慢了,但牺牲了速度却保证了数据的安全: 模拟查票抢票: import json import time from multiprocess

实现同步与互斥的一个实例--生产者消费模型

1.基础知识 1).生产者消费模型中存在3种关系: a.生产者与生产者之间是互斥的: b.消费者与消费者之间是互斥的: c.生产者与消费者之间是同步与互斥的: 2).生产者与消费者的场所,这儿我们选择单链表. 2.内容:多生产者生产一个结构体串在链表的表尾上,多消费者从表头取走结构体. 3.代码实现   1 #include<stdio.h>   2 #include<stdlib.h>   3 #include<pthread.h>   4    5 typedef 

11.python并发入门(part8 基于线程队列实现生产者消费者模型)

一.什么是生产者消费者模型? 生产者就是生产数据的线程,消费者指的就是消费数据的线程. 在多线程开发过程中,生产者的速度比消费者的速度快,那么生产者就必须等待消费者把数据处理完,生产者才会产生新的数据,相对的,如果消费者处理数据的速度大于生产者,那么消费者就必须等待生产者. 为了解决这种问题,就有了生产者消费者模型. 生产者与消费者模型,是通过一个容器,来解决生产者和消费者之间的耦合性问题,生产者和消费者之间并不会直接通信,这样生产者就无需等待消费者处理完数据,生产者可以直接把数据扔给队列,这个

【Windows】用信号量实现生产者-消费者模型

线程并发的生产者-消费者模型: 1.两个进程对同一个内存资源进行操作,一个是生产者,一个是消费者. 2.生产者往共享内存资源填充数据,如果区域满,则等待消费者消费数据. 3.消费者从共享内存资源取数据,如果区域空,则等待生产者填充数据. 4.生产者的填充数据行为和消费者的消费数据行为不可在同一时间发生. 下面用Windows的信号量以及线程等API模拟生产者-消费者模型 #include <Windows.h> #include <stdio.h> #define N 100 #d

Java实现多线程生产者消费模型及优化方案

生产者-消费者模型是进程间通信的重要内容之一.其原理十分简单,但自己用语言实现往往会出现很多的问题,下面我们用一系列代码来展现在编码中容易出现的问题以及最优解决方案. /* 单生产者.单消费者生产烤鸭 */class Resource { private String name; private int count = 1; //计数器,记录有多少只烤鸭被生产及消费 private boolean flag = false; //停止标记 public synchronized void set

python GIL锁 锁 线程池 生产者消费模型

python的GIL 锁 python内置的一个全局解释器锁 , 锁的作用就是保证同一时刻一个进程中只有一个线程可以被cpu调度 为什么有这把GIL锁? python语言的创始人在开发这门语言时 , 目的快速把语言开发出来 , 如果加上GIL锁(C语言加锁) , 切换时按照100条字节指令来进行线程间的切换 锁 : 1.锁 : Lock(1次放1个) 线程安全 , 多线程操作时 , 内部会让所有线程排队处理 , 如 : list / dict / Queue 线程不安全 + 人  =>排队处理

基于线程实现的生产者消费者模型(Object.wait(),Object.notify()方法)

需求背景 利用线程来模拟生产者和消费者模型 系统建模 这个系统涉及到三个角色,生产者,消费者,任务队列,三个角色之间的关系非常简单,生产者和消费者拥有一个任务队列的引用,生产者负责往队列中放置对象(id),消费者负责从队列中获取对象(id),其关联关系如下 方案1 因为是多线程操作,所以对任务的存取都要使用线程同步加锁机制,看一下我们的TaskQueue类,两个主方法都加了synchronized修饰,这就意味着,一个时间点只可能有一个线程对这个方法进行操作 TaskQueue类代码 [java

Unix IPC之Posix信号量实现生产者消费者

采用多生产者,多消费者模型. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /**  * 生产者  */ P(nempty); P(mutex); // 写入一个空闲位置 V(mutex); V(nstored); /**  * 消费者  */ P(nstored); P(mutex): // 清空一个非空闲位置 V(mutex); V(nempty); 全局性说明: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18