操作系统实验二之进程同步模拟
代码:
#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,对象被触发信号后,函数才会返回。