操作系统学习一(生产者与消费者问题)

在Linux环境下模拟生产者消费者问题

实验前知识准备

1.生产者消费者问题是一个著名的进程同步问题,本次实验中,用线程代替进程。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

源代码

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFFER_SIZE 10//缓冲池容量,选择循环队列这种数据结构
int* buffer;//指针在开辟空间时用到
int front = 0;//队头
int rear = 0;//队尾
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//POSIX 定义了一个宏
PTHREAD_MUTEX_INITIALIZER 来静态初始化互斥锁,在 LinuxThreads 实现中,
pthread_mutex_t 是一个结构,而 PTHREAD_MUTEX_INITIALIZER 则是一个结构常量
sem_t empty, full;//定义另一种信号量:条件变量
static void* Producer_T(void* arg) //生产者
{
printf("Producer run\n");
消费者
wait(full)
缓冲区非空
wait(mutex)
自缓冲区取出产品
结束
缓冲区被占用
缓冲区为空
signal(empty)
signal(mutex)
for (int i = 0; i < 10; i++) //生产 10 次 {
sem_wait(&empty);//是否有空余缓冲区,必须先 wait(empty)
pthread_mutex_lock(&mutex);//有空缓冲区就申请互斥锁修改缓冲区
buffer[front] = i;
front = (front + 1) % BUFFER_SIZE;//循环队列加一操作
printf("Producer: produce a good %d and put it into buffer\n", i);
pthread_mutex_unlock(&mutex);//放锁,和下面对 full 加一可以调换顺序
sem_post(&full);
sleep(1);//一秒生产一次
} }
static void* Consumer_T(void* arg) //消费者
{
printf("Consumer run\n");
for (int i = 0; i < 10; i++)
{
sem_wait(&full);//是否有存在产品的缓冲区,必须先 wait(full)
pthread_mutex_lock(&mutex);//有产品就申请互斥锁修改缓冲区
rear = (rear + 1) % BUFFER_SIZE;//循环队列减一操作
printf("Consumer: gain a good %d from buffer\n", buffer[rear]);
pthread_mutex_unlock(&mutex);//放锁,和下面对 empty 加一可以调换顺序
sem_post(&empty);
sleep(5);//五秒取一次产品
} }
int main()
{
pthread_t Producer, Consumer;//管理两个线程
void* Ret_P, * Ret_C;//两个空指针,作为创建线程时的一个参数
buffer = (int*)malloc(BUFFER_SIZE * sizeof(int));//给循环队列动态分配BUFFER_SIZE 大小的空间
if (pthread_create(&Producer, NULL, Producer_T, NULL) != 0 ||
pthread_create(&Consumer, NULL, Consumer_T, NULL) != 0)
{
printf("pthread_create error\n");
return -1;
}//生产者消费者两个线程创建是否成功
if ( sem_init(&empty, 0, BUFFER_SIZE) == -1||sem_init(&full, 0, 0) == -1 )
{
printf("sem_init error\n");
return -2;//信号量初始化是否成功
}
//后续都为资源的回收工作
pthread_join(Producer, &Ret_P);
pthread_join(Consumer, &Ret_C);//考虑到在多线程的程序中,主控线程一旦运行结束,所有的相关子线程将也会被强制结束。调用 pthread_join(),一方面使主线程等待子线程运行结束再运行,给子线程运行时间,另一方面,可以回收线程资源
free(buffer);
sem_destroy(&full);
sem_destroy(&empty);
return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
(1)创建生产者消费者线程 在Windows2000环境下,创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。这些线程的信息由本程序定义的“测试用例文件”中予以指定。 该文件的格式和含义如下: 3 1 P 3 2 P 4 3 C 4 1 4 P 2 5 C 3 1 2 4 第一行说明程序中设置几个临界区,其余每行分别描述了一个生产者或者消费者线程的信息。每一行的各字段间用Tab键隔开。不管是消费者还是生产者,都有一个对应的线程号,即每一行开始字段那个整数。第二个字段用字母P或者C区分是生产者还是消费者。第三个字段表示在进入相应线程后,在进行生产和消费动作前的休眠时间,以秒计时;这样做的目的是可以通过调整这一列参数,控制开始进行生产和消费动作的时间。如果是代表生产者,则该行只有三个字段。如果代表消费者,则该行后边还有若干字段,代表要求消费的产品所对应的生产者的线程号。所以务必确认这些对应的线程号存在并且该线程代表一个生产者。 (2)生产和消费的规则 在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求: ①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。 ②从上边的测试数据文件例子可以看出,某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲区才可以被释放,并作为空闲空间允许新的生产者使用。 ③每个消费者线程的各个消费需求之间存在先后顺序。例如上述测试用例文件包含一行信息“5 C 3 l 2 4”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。 ④要求在每个线程发出读写操作申请、开始读写操作和结束读写操作时分别显示提示信息。 (3)相关基础知识 本实验所使用的生产者消费者模型具有如下特点: 本实验的多个缓冲区不是环形循环的,也不要求按顺序访问。生产者可以把产品放到目前某一个空缓冲区中。 消费者只消费指定生产者的产品。 在测试用例文件中指定了所有的生产和消费的需求,只有当共享缓冲区的数据满足了所有关于它的消费需求后,此共享缓冲区才可以作为空闲空间允许新的生产者使用。 本实验在为生产者分配缓冲区时各生产者间必须互斥,此后各个生产者的具体生产活动可以并发。而消费者之间只有在对同一产品进行消费时才需要互斥,同时它们在消费过程结束时需要判断该消费对象是否已经消费完毕并清除该产品。 Windows用来实现同步和互斥的实体。在Windows中,常见的同步对象有:信号量(Semaphore)、互斥量(Mutex)、临界段(CriticalSection)等。使用这些对象都分为三个步骤,一是创建或者初始化:接着请求该同步对象,随即进入临界区,这一步对应于互斥量的上锁;最后释放该同步对象,这对应于互斥量的解锁。这些同步对象在一个线程中创建,在其他线程中都可以使用,从而实现同步互斥。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值