实验、进程的同步与互斥——生产者消费者
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验、进程的同步与互斥——⽣产者消费者
1. 1. 实验⽬的
两个或两个以上的进程,不能同时进⼊关于同⼀组共享变量的临界区域,否则可能发⽣与时间有关的错误,这种现象被称作进程互斥。
对CPU的速度和数⽬不做出任何假设的前提下,并发进程互斥访问临界资源,是⼀个较好的解决⽅案。
另外,还需要解决异步环境下的进程同步问题。
所谓异步环境是指:相互合作的⼀组并发进程,其中每⼀个进程都以各⾃独⽴的、不可预知的速度向前推进;但它们⼜需要密切合作,以实现⼀个共同的任务,即彼此“知道”相互的存在和作⽤。
实验⽬的:分析进程争⽤资源的现象,学习解决进程同步与互斥的⽅法。
本实验属于设计型实验,实验者可根据⾃⾝情况选⽤合适的开发环境和程序架构。
1. 2. 实验原理
信号量的PV操作与处理相关,P表⽰通过的意思,V表⽰释放的意思。
1962年,狄克斯特拉离开数学中⼼进⼊位于荷兰南部的艾恩德霍芬技术⼤学(Eindhoven Technical University)任数学教授。
在这⾥,他参加了X8计算机的开发,设计与实现了具有多道程序运⾏能⼒的操作系统——THE Multiprogramming System。
THE是艾恩德霍芬技术⼤学的荷兰⽂Tchnische Hoogeschool Eindhov –en的词头缩写。
狄克斯特拉在THE这个系统中所提出的⼀系统⽅法和技术奠定了计算机现代操作系统的基础,尤其是关于多层体系结构,顺序进程之间的同步和互斥机制这样⼀些重要的思想和概念都是狄克斯特拉在THE中⾸先提出并为以后的操作系统如UNIX等所采⽤的。
为了在单处理机的情况下确定进程(process)能否占有处理机,狄克斯特拉将每个进程分为“就绪”(ready)、“运⾏”(running)和“阻塞”(blocking)三个⼯作状态。
由于在任⼀时刻最多只有⼀个进程可以使⽤处理机,正占⽤着处理机的进程称为“运⾏”进程。
当某进程已具备了使⽤处理机的条件,⽽当前⼜没有处理机供其使⽤,则使该进程处于“就绪”状态。
当运⾏进程由于某种原因⽆法继续运⾏下去时,就停⽌其占⽤处理机,使之进⼊“阻塞”状态,待造成其退出运⾏的条件解除,再进⼊“就绪”状态。
⽽对系统中所有同时运⾏的进程(在⼀个进程访问共享数据时,另⼀个进程不访问该数据),存在同步和互斥(mutually- exclusive,指两个进程不能同时在⼀个临界区中使⽤同⼀个可重复使⽤的资源,诸如读写缓冲区)两个关系,狄克斯特拉巧妙地利⽤⽕车运⾏控制系统中的“信号量”(semaphore,或叫”信号灯”)概念加以解决。
所谓信号量,实际上就是⽤来控制进程状态的⼀个代表某⼀资源的存储单元。
例如,P1和P2是分别将数据送⼊缓冲B和从缓冲B读出数据的两个进程,为了防⽌这两个进程并发时产⽣错误,狄克斯特拉设计了⼀种同步机制叫“PV操作”,P操作和V操作是执⾏时不被打断的两个操作系统原语。
执⾏P操作P(S)时信号量S的值减1,若结果不为负则P(S)执⾏完毕,否则执⾏P操作的进程暂停以等待释放。
执⾏V操作V(S)时,S的值加1,若结果不⼤于0则释放⼀个因执⾏P(S)⽽等待的进程。
对P1和P2可定义两个信号量S1和S2,初值分别为1和0。
进程P1在向缓冲B送⼊数据前执⾏P操作P(S1),在送⼊数据后执⾏V操作V(S2)。
进程P2在从缓冲B读取数据前先执⾏P操作
P(S2),在读出数据后执⾏V操作V(S1)。
当P1往缓冲B送⼊⼀数据后信号量S1之值变为0,在该数据读出后S1之值才⼜变为1,因此在前⼀数未读出前后⼀数不会送⼊,从⽽保证了P1和P2之间的同步。
这⼀同步机制叫PV操作,这是狄克斯特拉⽤荷兰⽂定义的,因为在荷兰⽂中,通过叫passeren,释放叫vrijgeven,PV操作因此得名。
这是在计算机术语中不是⽤英语表达的极少数的例⼦之⼀。
1. 3. 实验内容
以下是进程同步与互斥的典型问题例析——⽣产者消费者,请模拟它的实现过程。
问题描述:⼀个仓库可以存放K件物品。
⽣产者每⽣产⼀件产品,将产品放⼊仓库,仓库满了就停⽌⽣产。
消费者每次从仓库中去⼀件物品,然后进⾏消费,仓库空时就停⽌消费。
数据结构:进程:Producer - ⽣产者进程,Consumer - 消费者进程
buffer: array [0..k-1] of integer;
in,out: 0..k-1;
in记录第⼀个空缓冲区,out记录第⼀个不空的缓冲区
s1,s2,mutex: semaphore;
s1控制缓冲区不满,s2控制缓冲区不空,mutex保护临界区;
初始化s1=k,s2=0,mutex=1
4. 实验步骤
i. 选⽤合适的实验程序开发环境。
ii. 设计程序结构,规划程序功能。
iii. 完成程序的编码与测试。
iv. 设计实验数据。
v. 针对实验数据运⾏程序,并将结果记录在实验报告上。
5. 代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>
#define Maxbuf 10
#define TimesOfOp 10
#define true 1
#define false 0
struct Circlebuf
{
int read;
int write;
int buf[Maxbuf];
} circlebuf;
sem_t mutex;//
sem_t empty;//
sem_t full;//
void writeCirclebuf(struct Circlebuf *circlebuf, int *value)
{
circlebuf->buf[circlebuf->write] = (*value);
circlebuf->write=(circlebuf->write+1)%Maxbuf;
}
int readCirclebuf(struct Circlebuf *circlebuf)
{
int value = 0;
value = circlebuf->buf[circlebuf->read];
circlebuf->buf[circlebuf->read] = 0;
circlebuf->read = (circlebuf->read + 1) % Maxbuf;
return value;
}
void OutCirclebuf(struct Circlebuf *circlebuf)
{
int i;
printf("+++++缓冲区各单元的值.\n");
for (i = 0; i <Maxbuf; i++)
printf("%d ", circlebuf->buf[i]);
printf("\n");
}
void sigend(int sig)
{
exit(0);
}
void *productThread(void *i)
{
int *n = (int *)i;
int t = TimesOfOp;
while (t--)
{
sem_wait(&empty);//
sem_wait(&mutex);//
writeCirclebuf(&circlebuf, n);
printf("----------------⽣产者%d 写⼊缓冲区的值%d \n", *n, *n); OutCirclebuf(&circlebuf);
sem_post(&mutex);
sem_post(&full);
}
}
void *consumerThread(void *i)
{
int *n = (int *)i;
int value = 0;
int t = TimesOfOp;
while (t--)
{
sem_wait(&full);
sem_wait(&mutex);
value = readCirclebuf(&circlebuf);
printf("----------------消费者%d 取⾛产品的值%d \n",*n,value); OutCirclebuf(&circlebuf);
sem_post(&mutex);
sem_post(&empty);
}
}
main()
{
int i;
int ConsNum = 0, ProdNum = 0, ret;
pthread_t cpid, ppid;//
sem_init(&mutex, 0, 1);
sem_init(&empty, 0, Maxbuf);
sem_init(&full, 0, 0);
signal(SIGINT, sigend);
signal(SIGTERM, sigend);
circlebuf.read = circlebuf.write = 0;
for ( i = 0; i < Maxbuf; i++)
circlebuf.buf[i] = 0;
printf("请输⼊⽣产者的数⽬ :");
scanf("%d",&ProdNum);
int *pro=(int*)malloc(ProdNum*sizeof(int));
printf("请输⼊消费者的数⽬ :");
scanf("%d", &ConsNum);
int *con = (int *)malloc(ConsNum * sizeof(int));
for ( i = 1; i <= ConsNum; i++)
{
cpid = i;
con[i - 1] = i;
ret = pthread_create(&cpid, NULL, consumerThread,(void*)&con[i-1] ); if (ret != 0)
{
printf("Create thread error");
exit(1);
}
}
for (i = 1; i <= ProdNum; i++)
{
ppid = i + 100;
pro[i - 1] = i;
ret = pthread_create(&ppid, NULL, productThread, (void *)&pro[i - 1]); if (ret != 0)
{
printf("Create thread error");
exit(1);
}
}
sleep(1);
sem_destroy(&mutex);//
sem_destroy(&empty);//
sem_destroy(&full);//
pthread_exit(NULL);//
}。