生产者/消费者的进程同步模拟

操作系统实验二之进程同步模拟

代码:

#include"stdio.h"
#include"stdlib.h"
#include 
#include"windows.h"

#define P(sem) WaitForSingleObject(sem,INFINITE)//P操作,sem为指定线程,INFINITE为等待时间(无限等待)
#define V(sem) ReleaseSemaphore(sem,1,NULL)//V操作,增加信号量

typedef struct Node{
	int product;//产品,用整数表示产品序号
	struct Node *next;
}*buffer;

buffer head=(buffer)malloc(sizeof(struct Node));//初始化缓冲区链表,head->next=NULL
buffer tail=head;//tail始终指向链表尾部

static int products_ID=0;//产品序号
const int buf_size=10;//缓冲区大小
const int producer_num=1;//生产者数量
const int consumer_num=8;//消费者数量

HANDLE empty,occupy,mutex;//三个信号量:空缓冲区数,产品数,缓冲区的互斥使用

void add(){//向缓冲区加一个元素(链表尾)
	products_ID++;
	buffer p;
	p=(buffer)malloc(sizeof(struct Node));
	tail->next=p;
	tail=p;
}
void remove(){//读出并移除缓冲区的一个元素(链表头)
	buffer p0=head->next;
	//printf("%d",p0->product);
	head->next=p0->next;
}
void ProducerThread(void* param){//生产者
	int id=*(int*)param;
	while(1){
		P(empty);
		P(mutex);
		Sleep(500);
		printf("Producer_%d produced %d号产品\n",id,products_ID);
		add();
		V(mutex);
		V(occupy);
	}
}
void ConsumerThread(void* param){//消费者
	int id=*(int*)param;
	while(1){
		P(occupy);
		P(mutex);
		Sleep(500);
		printf("Consumer_%d consumed **%d号产品\n",id,products_ID-2);
		remove();
		V(mutex);
		V(empty);
	}
}
int main(){
	int i;
	int p_id[producer_num],c_id[consumer_num];

	//创建信号量
	occupy=CreateSemaphore(NULL,0,buf_size,NULL);//已有产品数量,区间为0-buf_size
	//1'安全属性指针,一般设置为NULL
	//2'信号量初值
	//3'允许的最大值
	//4'信号量名字,一般为NULL,表示信号量局限于一个进程中;若给予一个名,则其它进程也可以使用该信号量。

	empty=CreateSemaphore(NULL,buf_size,buf_size,NULL);//空余缓冲区数量

	mutex=CreateSemaphore(NULL,1,1,NULL);//互斥量

	for(i=0;i<producer_num;i++){
		p_id[i]=i+1;//生产者编号
		_beginthread(ProducerThread,0,p_id+i);//创建线程
		//_beginthread(void(*start_address)(void*),unsigned stack_size,void *arglist)
		//start_address:程序执行一个新线程的起始地址,一般就是执行某个函数,此参数就是函数名
        //stack_size:新线程的堆栈大小或0,一般为0
        //Arglist:传给新线程的变量清单或空,若不需传递,则这里就是NULL,若要传递,一般这里会是个指针
	}
	for(i=0;i<consumer_num;i++){
		c_id[i]=i+1;
		_beginthread(ConsumerThread,0,c_id+i);
	}
	while(getchar()=='\n')
		break;
	return 0;
}

实验内容:
2.1 实验目的

了解Windows环境下信号量的实现方法,进一步加深对进程同步机制的理解。

2.2 实验准备

(1)查资料学习如:创建线程的函数_beginthread( )、创建信号量函数CreateSemaphore( )等,了解这几个函数的使用方法。

(2)熟悉并理解生产者/消费者问题。

2.3 实验内容

(1)问题描述

编程实现生产者/消费者的同步问题。

(2)基本要求

    ²  利用创建的线程模拟进程;

    ²  需显示哪个生产者创建了哪一个产品,以及哪个消费者消费了哪个产品,即生产和消费的流水账。例如:

            n  生产者A生产了1号产品

            n  生产者B生产了2号产品

            n  消费者a消费了1号产品

² 通过设置不同生产者线程数和消费者线程数,并观察流水记录,从而判断你编写的同步算法的正确性。

2.4 实现提示

(1)设计在同一个进程地址空间内执行的多个线程:生产者线程和消费者线程;

(2)生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费;

(3)消费者线程从缓冲区中获得物品,然后释放缓冲区;

(4)生产者线程生产物品时,若无空缓冲区可用,生产者线程必须等待消费者线程释放出一个空缓冲区;

(5)消费者线程消费物品时,若无物品,消费者线程将被阻塞,直到新的物品被生产出来。

(6)需要使用如下三个信号量:

² 一个互斥信号量,用以阻止生产者线程和消费者线程同时操作缓冲区列表;

² 一个信号量,用于当缓冲区满时让生产者线程等待;

² 一个信号量,用于当缓冲区空时让消费者线程等待。

(7)学有余力的同学可同时实现在Linux操作系统下的生产者消费者问题。

(8)查资料熟悉如下函数和原语的使用方法(对于本实验的完成是至关重要的)

_beginthread函数说明

    _beginthread( void( *start_address)( void * ), unsigned stack_size, void *arglist)//创建线程

    start_address:程序执行一个新线程的起始地址,一般就是执行某个函数,此参数就是函数名

    stack_size:新线程的堆栈大小或0,一般为0

    Arglist:传给新线程的变量清单或空,若不需传递,则这里就是NULL,若要传递,一般这里会是个指针

信号量包含的几个操作原语:

CreateSemaphore(SecAttr, InitialCoutn,MaxCount, SemName)//创建一个信号量

    SecAttr:安全属性指针,一般设置为NULL

    InitialCoutn:信号量初值

    MaxCount:允许的最大值

    SemName:信号量名字,一般为NULL,表示信号量局限于一个进程中;若给予一个名,则其它进程也可以使用该信号量。

    例如:mutex =CreateSemaphore(NULL,1,1,NULL),则mutex就是信号量  

ReleaseSemaphore(Semaphore, ReleaseCount,PreviousCount )//释放信号量,就是V操作

    Semaphore:信号量

    ReleaseCount:递增数量。若为1,则每次增加1

    PreviousCount:先前的值,若不需要信号量上次的值,则这个参数可置为NULL  

WaitForSingleObject(hHandle,dwMilliseconds) //等待信号,就是P操作

    hHandle:对象句柄,可以指定一系列的对象,如Event、Job、Memoryresource notification、Mutex、Process、Semaphore、Thread、Waitabletimer等,在本实验中就是信号量。

    dwMilliseconds:定时时间间隔,单位为毫秒。若指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。若为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。若为INFINITE,对象被触发信号后,函数才会返回。

你可能感兴趣的:(生产者/消费者的进程同步模拟)