生产者消费者之信号量的使用

实验报告

一、实验目的

1.熟悉临界资源、信号量及PV操作的定义与物理意义

2.了解进程通信的方法

3.掌握进程互斥与同步的相关知识

4.掌握用信号量机制解决进程之间的同步与互斥问题

5.实现生产者-消费者问题,深刻理解进程同步问题

二、实验环境

Linux系统

三、实验内容

在Linux操作系统下用C或C++实现经典同步问题:生产者-消费者问题,具体要求如下:

1. 一个大小为10的缓冲区,初始状态为空。

2. 2个生产者,随机等待一段时间,往缓冲区中添加数据,若缓冲区已满,等待消费者取走数据之后再添加,重复10次。

3. 2个消费者,随机等待一段时间,从缓冲区中读取数据,若缓冲区为空,等待生产者添加数据之后再读取,重复10次。

四、程序实现

1.程序中使用的数据结构及说明

1.1缓冲区

缓冲区采用循环队列表示,利用头、尾指针来存放、读取数据,以及判断队列是否为空。缓冲区中数组大小为10。

#define BUFFERNUM 10

//缓冲区队列

struct Buffer_Queue {

char production[BUFFERNUM];  //产品

int front, rear;             //头指针和尾指针

int num;                     //缓冲区里面字母数量

};

1.2信号量

相关信号量的定义采用semaphore.h里面附带的结构

/*信号量*/

//空的信号量和满的信号量

sem_t empty_sem, full_sem;

//静态创建条件变量

pthread_cond_t full = PTHREAD_COND_INITIALIZER;        //满的变量

pthread_cond_t empty = PTHREAD_COND_INITIALIZER;       //空的变量

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;      //互斥锁

2.核心算法

2.1生产者

void *producer(void *arg)

{

struct Buffer_Queue *q;

q = (struct Buffer_Queue *) arg;

while(1)

{

pthread_mutex_lock(&lock);

while (q->num == BUFFERNUM)    //缓冲区已经满了,等待

{

pthread_cond_wait(&full, &lock);

}

sem_wait(&empty_sem);

/*生产产品*/

char c = getRandChar();                                      //随机获取字母

q->rear = (q->rear + 1) % BUFFERNUM;                         //计算新的尾指针

q->production[q->rear] = c;                                  //写入新产品

q->num++;

sem_post(&full_sem);

if (q->num == 1) {

pthread_cond_signal(&empty);

}

pthread_mutex_unlock(&lock);

sleep(rand() % 2);

}

}

2.2消费者

void *consumer(void *arg)

{

struct Buffer_Queue *q;

q = (struct Buffer_Queue *) arg;

while(1)

{

pthread_mutex_lock(&lock);

while (q->num == 0)           //缓冲区已经空了,等待

{

pthread_cond_wait(&empty, &lock);

}

sem_wait(&full_sem);

/*消费产品*/

q->front = (q->front + 1) % BUFFERNUM;    //计算新的头指针

char c = q->production[q->front];         //消费产品

q->production[q->front] = ‘ ‘;            //

q->num--;

sem_post(&empty_sem);

if (q->num == BUFFERNUM - 1) {

pthread_cond_signal(&full);

}

pthread_mutex_unlock(&lock);

sleep(rand() % 2);

}

}

3.源程序及注释

#include <pthread.h>

#include <stdio.h>

#include <semaphore.h>

#include <time.h>

/*信号量*/

//空的信号量和满的信号量

sem_t empty_sem, full_sem;

//静态创建条件变量

pthread_cond_t full = PTHREAD_COND_INITIALIZER;        //满的变量

pthread_cond_t empty = PTHREAD_COND_INITIALIZER;       //空的变量

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;      //互斥锁

#define BUFFERNUM 10

//缓冲区队列

struct Buffer_Queue {

char production[BUFFERNUM];  //产品

int front, rear;             //头指针和尾指针

int num;                     //缓冲区里面字母数量

};

//输出设计者信息

void printDesign()

{

printf("   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");

printf("   ┃         生产者-消费者问题实现    ┃\n");

printf("   ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n");

}

//随机产生生产字符

char getRandChar()

{

int temp = rand()%26;

return (‘a‘+temp);

}

//打印进程运行结果

void printTime()

{

//打印时间

time_t now;

struct tm *timenow;         //实例化tm结构指针

time(&now);

timenow = localtime(&now);

printf("执行时间: %s ",asctime(timenow));

}

//生产者1

void *producer1(void *arg)

{

struct Buffer_Queue *q;

q = (struct Buffer_Queue *) arg;

while(1)

{

pthread_mutex_lock(&lock);

while (q->num == BUFFERNUM)    //缓冲区已经满了,等待

{

pthread_cond_wait(&full, &lock);

}

sem_wait(&empty_sem);

/*生产产品*/

char c = getRandChar();                                      //随机获取字母

q->rear = (q->rear + 1) % BUFFERNUM;                         //计算新的尾指针

q->production[q->rear] = c;                                  //写入新产品

q->num++;

/*打印输出结果*/

printf("-------------------------------------------------------------\n");

printTime();              //程序运行时间

int i;

printf("缓冲区数据(%d个):",q->num);                  //打印缓冲区中的数据

if(q->front < q->rear)

{

for(i = q->front; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

else

{

for(i = q->front; i < BUFFERNUM; i++)

printf("%c ",q->production[i]);

for(i = 0; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

printf("\n当前执行的进程:生产者1\n");   //打印当前执行的进程

printf("产生的数据:%c\n",c);      //打印产生或消费的数据

printf("-------------------------------------------------------------\n");

sem_post(&full_sem);

if (q->num == 1) {

pthread_cond_signal(&empty);

}

pthread_mutex_unlock(&lock);

sleep(rand() % 2);

}

}

//生产者2

void *producer2(void *arg)

{

struct Buffer_Queue *q;

q = (struct Buffer_Queue *) arg;

while(1)

{

pthread_mutex_lock(&lock);

while (q->num == BUFFERNUM)    //缓冲区已经满了,等待

{

pthread_cond_wait(&full, &lock);

}

sem_wait(&empty_sem);

/*生产产品*/

char c = getRandChar();                                      //随机获取字母

q->rear = (q->rear + 1) % BUFFERNUM;                         //计算新的尾指针

q->production[q->rear] = c;                                  //写入新产品

q->num++;

/*打印输出结果*/

printf("-------------------------------------------------------------\n");

printTime();              //程序运行时间

int i;

printf("缓冲区数据(%d个):",q->num);                   //打印缓冲区中的数据

if(q->front < q->rear)

{

for(i = q->front; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

else

{

for(i = q->front; i < BUFFERNUM; i++)

printf("%c ",q->production[i]);

for(i = 0; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

printf("\n当前执行的进程:生产者2\n");   //打印当前执行的进程

printf("产生的数据:%c\n",c);      //打印产生或消费的数据

printf("-------------------------------------------------------------\n");

sem_post(&full_sem);

if (q->num == 1) {

pthread_cond_signal(&empty);

}

pthread_mutex_unlock(&lock);

sleep(rand() % 2);

}

}

//消费者1

void *consumer1(void *arg)

{

struct Buffer_Queue *q;

q = (struct Buffer_Queue *) arg;

while(1)

{

pthread_mutex_lock(&lock);

while (q->num == 0)           //缓冲区已经空了,等待

{

pthread_cond_wait(&empty, &lock);

}

sem_wait(&full_sem);

/*消费产品*/

q->front = (q->front + 1) % BUFFERNUM;    //计算新的头指针

char c = q->production[q->front];         //消费产品

q->production[q->front] = ‘ ‘;            //

q->num--;

/*打印输出结果*/

printf("-------------------------------------------------------------\n");

printTime();              //程序运行时间

int i;

printf("缓冲区数据(%d个):",q->num);                   //打印缓冲区中的数据

if(q->front < q->rear)

{

for(i = q->front; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

else

{

for(i = q->front; i < BUFFERNUM; i++)

printf("%c ",q->production[i]);

for(i = 0; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

printf("\n当前执行的进程:消费者1\n");   //打印当前执行的进程

printf("消耗的数据:%c\n",c);      //打印产生或消费的数据

printf("-------------------------------------------------------------\n");

sem_post(&empty_sem);

if (q->num == BUFFERNUM - 1) {

pthread_cond_signal(&full);

}

pthread_mutex_unlock(&lock);

sleep(rand() % 2);

}

}

//消费者2

void *consumer2(void *arg)

{

struct Buffer_Queue *q;

q = (struct Buffer_Queue *) arg;

while(1)

{

pthread_mutex_lock(&lock);

while (q->num == 0)           //缓冲区已经空了,等待

{

pthread_cond_wait(&empty, &lock);

}

sem_wait(&full_sem);

/*消费产品*/

q->front = (q->front + 1) % BUFFERNUM;    //计算新的头指针

char c = q->production[q->front];         //消费产品

q->production[q->front] = ‘ ‘;            //

q->num--;

/*打印输出结果*/

printf("-------------------------------------------------------------\n");

printTime();              //程序运行时间

int i;

printf("缓冲区数据(%d个):",q->num);                   //打印缓冲区中的数据

if(q->front < q->rear)

{

for(i = q->front; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

else

{

for(i = q->front; i < BUFFERNUM; i++)

printf("%c ",q->production[i]);

for(i = 0; i <= q->rear; i++)

printf("%c ",q->production[i]);

}

printf("\n当前执行的进程:消费者1\n");   //打印当前执行的进程

printf("消耗的数据:%c\n",c);      //打印产生或消费的数据

printf("-------------------------------------------------------------\n");

sem_post(&empty_sem);

if (q->num == BUFFERNUM - 1) {

pthread_cond_signal(&full);

}

pthread_mutex_unlock(&lock);

sleep(rand() % 2);

}

}

int main(int argc, char *argv[])

{

//输出设计者

printDesign();

/*创建缓冲区*/

//定义

struct Buffer_Queue *q;

q = (struct Buffer_Queue *) malloc(sizeof(struct Buffer_Queue));

//初始化队列

q->front = q->rear = BUFFERNUM - 1;

q->num = 0;

/*执行进程*/

//定义四个线程

pthread_t pid1, cid1, pid2, cid2;

//初始化信号量

sem_init(&empty_sem, 0, BUFFERNUM);

sem_init(&full_sem, 0, 0);

//创建线程

pthread_create(&pid1, NULL, producer1, (void *) q);

pthread_create(&cid1, NULL, consumer1, (void *) q);

pthread_create(&pid2, NULL, producer2, (void *) q);

pthread_create(&cid2, NULL, consumer2, (void *) q);

//销毁线程

pthread_join(pid1, NULL);

pthread_join(cid1, NULL);

pthread_join(pid2, NULL);

pthread_join(cid2, NULL);

//销毁信号量

sem_destroy(&empty_sem);

sem_destroy(&full_sem);

return 0;

}

五、运行结果

1.linux环境下,用gcc编译

1.1编译

1.2执行结果

截图1

截图2

截图3

时间: 2024-08-11 15:39:57

生产者消费者之信号量的使用的相关文章

Operating System-进程/线程内部通信-信号量、PV操作的实现和应用(解决哲学家进餐和生产者消费者问题)

本文主要内容: 信号量的实现 利用信号量解决哲学家用餐问题 利用信号量解决生产者消费者问题 一.信号量的实现 1.1 信号量结构 typedef struct { int value; struct process * list } semaphore; value代表当前信号量可以使用的数量,list代表当前信号量上所等待的进程. 1.2 P操作实现 P(semaphore * s) { s.value--; if(s.value < 0) { add current process to s

Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post 有名信号量 #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <semaphore.h> sem_t *sem_open(co

用信号量解决生产者消费者问题

用信号量解决生产者消费者问题: ipc.h #ifndef _IPC_H_ #define _IPC_H_ #include <sys/types.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include <errno.h> #include <stdio.h> #include <st

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

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

Linux下用环形buf以及POSIX版本信号量解决生产者消费者问题

一.Semaphore(信号量) Mutex变量是非0即1的,可看作一种资源的可用数量,初始化时Mutex是1,表示有一个可用资源, 加锁时获得该资源,将Mutex减到0,表示不再有可用资源,解锁时释放该资源,将Mutex重新加到1,表示又有了一个可用资源. 信号量(Semaphore)和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1. 即,如果信号量描述的资源数目是1时,此时的信号量和互斥锁相同! 本次使用的是POSIX semaphore库函数,这种信号量不仅可以

13 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件  queue队列 生产者消费者模型 Queue队列 开发一个线程池

本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Queue队列 开发一个线程池 进程 语法 进程间通讯 进程池 操作系统发展史 手工操作(无操作系统) 1946年第一台计算机诞生--20世纪50年代中期,还未出现操作系统,计算机工作采用手工操作方式. 手工操作程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把

生产者消费者问题(基于线程和无名信号量)

//5.生产者消费者问题 #include <pthread.h> #include <semaphore.h> #include <unistd.h> #include <stdio.h> #define MAX 50 #define BUFSIZE 10 //仓库的大小 int buf[BUFSIZE]={0}; int in=0; int out=0; sem_t full,empty; void* producer(void* arg) { int

多线程实现生产者消费者问题 详细注释 事件+临界区 信号量+临界区2种方法

生产者消费者问题:  该问题描述了两个共享固定大小缓冲区的线程--即所谓的"生产者"和"消费者"--在实际运行时会发生的问题.生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程.与此同时,消费者也在缓冲区消耗这些数据.该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据.具体我就不解释了   应该都懂 不懂请百度一下 我是用事件实现生产者消费者问题的同步  用临界区实现互斥    我的这个做法与经典做法不同 即用信号量

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

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