一、问题描述:
有五个哲学家围坐在一圆桌旁,桌中央有一盘通心粉,每人面前有一只空盘子,每两人之间放一只筷子每个哲学家的行为是思考,感到饥饿,然后吃通心粉.为了吃通心粉,每个哲学家必须拿到两只筷子,并且每个人只能直接从自己的左边或右边去取筷子。
二、防止死锁发生的分配方式:
仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子。这样要么一次占有两只筷子(所有线程需要的资源)进行下一步的吃通心粉,然后释放所有的资源;要么不占用资源,这样就不可能产生死锁了。
三、产生死锁的分配方式:
当筷子(资源)可用时,先分配左边的筷子,等待一会后再分配右边的筷子,由于这个过程中,左边的筷子一直没有释放,就有可能产生死锁了。
四、程序运行说明
程序运行过程中会弹出一个MessageBox提示操作者操作:
1.第一个对话框用于选择运行模式
a.选择yes 表示采用的是运行的防止死锁的方式,这样的话整个程序可以一直运行下去,不会产生死锁。
b.选择no 表示运行产生死锁的方式会弹出第二个对话框。
2.第二个对话框用于选择运行时,线程运行的时间
a. 选择 res 线程时间比较短,很快就可以死锁
b.选择no 线程时间跟选择yes 时候的时间差不多,产生死锁的时间稍微长一点
五、关于哲学家就餐问题的程序代码分析:
A. Dining.c
变量说明:
HINSTANCE hInst | 应用实例句柄 |
HWND hWndMain | 主窗口句柄 |
HBITMAP hbmpOffscreen | 位图句柄 |
BOOL bWaitMultiple | 用于选择等待的方式(要么死锁,要么一直循环运行) |
BOOL bFastFood; | 用于选择进程等待的时间 |
extern int gDinerState[] | 用于表示哲学家的状态(外部接口) |
extern int gChopstickState[] | 用于表示筷子的状态 |
extern HANDLE gchopStick[PHILOSOPHERS] | 筷子的数组 |
函数说明:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | 处理消息函数: 根据进程调度的消息的不同处理不同的消息包括:关闭窗口,销毁资源,画窗口,和重画窗口等
|
BOOL CreateOffscreen() | 获得当前窗口的一个位图句柄 |
void RenderOffscreen(HDC hDestDC) | 通过位图句柄画演示的界面 1.先画桌子,再画筷子,再画盘子, 2.再画哲学家: 哲学家用圆表示,根据哲学家的状态选择画笔(为resting 状态时为绿色圆圈,为等待或者,就餐时为红色圆圈) 3.最后画哲学家的手: 判断的依据是若筷子的编号和哲学家的编号一致,那么认为这根筷子属于这个哲学家(筷子资源空闲)那么可以画手表示哲学家获得了这个筷子。(获得资源)
|
BOOL InitApplication(HINSTANCE hInstance) | 初始化应用窗口
|
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) | 初始化主窗口 弹出选择对话框进行模式选择,并启动进程
|
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
| 调用前面的函数并对进线程消息进行处理
|
B.Mutex.c
变量说明:
extern HWND hWndMain | 在Dining.c中定义是这个文件的外部接口 |
extern BOOL bWaitMultiple
| 在Dining.c中定义是这个文件的外部接口 |
extern BOOL bFastFood | 在Dining.c中定义是这个文件的外部接口 |
int gDinerState[PHILOSOPHERS] | 哲学家状态数组 |
int gChopstickState[PHILOSOPHERS]
| 筷子状态数组 |
HANDLE gchopStick[PHILOSOPHERS] | 筷子状态数组
|
函数说明:
1. DWORD WINAPI PhilosopherThread(LPVOID pVoid)
哲学家进程:
用于分配给哲学家筷子(资源)通过开始运行时候的对话框的选择来控制资源的分配方式:两中分配方式见二、三所述。通过随机产生的时间来控制线程的运行,
每个哲学家的状态都是resting waiting eating,一直循环。
2.int Diner(void)
用于建立互斥的信号对象(筷子)和启动哲学家进程
/*
* Dining.c
*
* Sample code for "Multithreading Applications in Win32"
* This sample is discussed in Chapter 4.
*
* Graphically demonstrates the problem of the
* dining philosophers.
*/
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <windowsx.h>
#include <string.h>
#include <math.h>
#include "dining.h"
HINSTANCE hInst; // Application Instance Handle
HWND hWndMain; // Main Window Handle
HBITMAP hbmpOffscreen;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void RenderOffscreen(HDC hDestDC);
BOOL bWaitMultiple;
BOOL bFastFood;
extern int gDinerState[];
extern int gChopstickState[];
extern HANDLE gchopStick[PHILOSOPHERS]; // 1 chopstick between each philopher and his neighbor
/********************************************************************/
/* ROUTINE: WndProc */
/* */
/* PURPOSE: Processes messages */
/********************************************************************/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
switch (wParam)
{
case CM_EXIT:
PostMessage(hWndMain, WM_CLOSE, 0, 0L);
break;
}
break;
case WM_FORCE_REPAINT:
{
MSG msg;
InvalidateRect(hWndMain, NULL, TRUE);
while (PeekMessage(&msg, hWndMain, WM_FORCE_REPAINT,WM_FORCE_REPAINT,TRUE))
;
}
break;
case WM_PAINT:
hdc = BeginPaint(hWndMain, &ps);
RenderOffscreen(hdc);
EndPaint(hWndMain, &ps);
break;
case WM_CLOSE:
return DefWindowProc(hWndMain, message, wParam, lParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return (0);
}
BOOL CreateOffscreen()
{
HWND hwndScreen = GetDesktopWindow();
HDC hdc = GetDC(hwndScreen);
int nWidth = GetSystemMetrics( SM_CXSCREEN );
int nHeight = GetSystemMetrics( SM_CYSCREEN );
hbmpOffscreen = CreateCompatibleBitmap( hdc, nWidth, nHeight );
ReleaseDC(hwndScreen, hdc);
if ( !hbmpOffscreen )
return FALSE;
else
return TRUE;
}
void RenderOffscreen(HDC hDestDC)
{
HDC hdc = hDestDC; // CreateCompatibleDC(hWndMain);
int err=GetLastError();
HBITMAP hOldBitmap = SelectObject(hdc, hbmpOffscreen);
RECT rect;
HPEN hPen;
double dx, dy, px, py, AngRad, dDeltaAng;
int pos, p1;
long CenterX, CenterY;
hPen = SelectObject(hdc, CreatePen(PS_SOLID, 3, 0L));
GetClientRect(hWndMain, &rect);
/* Draw the table */
CenterX = (rect.right - rect.left)/2;
CenterY = (rect.bottom - rect.top)/2;
Ellipse(hdc, CenterX - 100, CenterY - 100, CenterX + 100, CenterY + 100);
/* Draw the chopsticks */
dDeltaAng = 360 / PHILOSOPHERS; //筷子间的角度差
for (pos = 0; pos < PHILOSOPHERS; pos++) //FIXIT
{
/* Draw the chopsticks */
AngRad = (pos * dDeltaAng)/57.29577951; //转化为弧度
dx = CenterX + (sin(AngRad)*60);
dy = CenterY - (cos(AngRad)*60);
MoveToEx(hdc, (int)dx, (int)dy, NULL);
dx = CenterX + (sin(AngRad)*85);
dy = CenterY - (cos(AngRad)*85);
LineTo(hdc, (int)dx, (int)dy);
//Draw the plate
AngRad = ((pos * dDeltaAng+dDeltaAng / 2))/57.29577951; //转化为弧度
dx = CenterX + (sin(AngRad) * 72);
dy = CenterY - (cos(AngRad) * 72);
Ellipse(hdc, (int)dx-12, (int)dy-12, (int)dx+12, (int)dy+12);
}
/* delete the black pen */
DeleteObject(SelectObject(hdc, hPen));
/* Draw the philosophers */
for(pos = 0; pos < PHILOSOPHERS; pos++)
{
/* select a pen for each philosopher */
switch (gDinerState[pos])
{
case RESTING:
hPen = SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(0, 255, 0)));
break;
case WAITING:
case EATING:
hPen = SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(255, 0, 0)));
break;
default:
hPen = SelectObject(hdc, CreatePen(PS_SOLID, 3, 0L));
}
AngRad = ((pos * dDeltaAng) + dDeltaAng / 2)/57.29577951;
px = CenterX + (sin(AngRad)*150);
py = CenterY - (cos(AngRad)*150);
/* Draw the Philosopher */
Ellipse(hdc, (int)px-25, (int)py-25, (int)px+25, (int)py+25);
//Draw the left arm
if (gChopstickState[pos] == pos)
{
MoveToEx(hdc, (int)px, (int)py, NULL);
AngRad = (pos * dDeltaAng)/57.29577951; //转化为弧度
dx = CenterX + (sin(AngRad)*85);
dy = CenterY - (cos(AngRad)*85);
LineTo(hdc, (int)dx, (int)dy);
}
//Draw the right arm
p1 = pos + 1;
if (p1 == PHILOSOPHERS)
p1 = 0;
if (gChopstickState[p1] == pos)
{
MoveToEx(hdc, (int)px, (int)py, NULL);
AngRad = (p1 * dDeltaAng)/57.29577951;
dx = CenterX + (sin(AngRad)*85);
dy = CenterY - (cos(AngRad)*85);
LineTo(hdc, (int)dx, (int)dy);
}
/* Delete the pen */
DeleteObject(SelectObject(hdc, hPen));
} //for pos
BitBlt( hDestDC,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom-rect.top,
hdc,
rect.left,
rect.top,
SRCCOPY
);
GetLastError();
SelectObject(hdc, hOldBitmap);
// DeleteDC(hWndMain, hdc);
}
/********************************************************************/
/* ROUTINE: InitApplication */
/* */
/* PURPOSE: Initialize the application */
/********************************************************************/
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = "din";
wc.lpszClassName = "dinWClass";
RegisterClass(&wc);
return TRUE;
}
/********************************************************************/
/* ROUTINE: InitInstance */
/* */
/* PURPOSE: Saves instance handle and creates main window */
/********************************************************************/
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
int ret;
hInst = hInstance;
hWndMain = CreateWindow(
"dinWClass",
"Dining Philosopher",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
450,
450,
NULL, NULL, hInstance, NULL );
if (!hWndMain)
return FALSE;
ShowWindow(hWndMain, nCmdShow);
UpdateWindow(hWndMain);
if (!CreateOffscreen())
PostQuitMessage(1);
ret = MessageBox(hWndMain, "你期望使用防死锁运行模式吗?/n/n"
"如果选择Yes, 程序将正常运行./n"
"如果选择No, 程序会进入死锁./n",
"Wait Mode", MB_YESNO);
if (ret == IDYES)
bWaitMultiple = TRUE;
else
{
bWaitMultiple = FALSE;
ret = MessageBox(hWndMain, "你期望快速进入死锁吗?/n/n"
"如果选择Yes, 将更快进入死锁./n",
"Wait Mode", MB_YESNO);
if (ret == IDYES)
bFastFood = TRUE;
else
bFastFood = FALSE;
}
// Start the threads
Diner();
return TRUE;
}
/********************************************************************/
/* FUNCTION: WinMain */
/* */
/* PURPOSE: Calls initialization function, processes message loop */
/********************************************************************/
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
int i;
if (!hPrevInstance)
if (!InitApplication(hInstance))
return (FALSE);
if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Clear the table
for (i = 0; i < PHILOSOPHERS; i++)
CloseHandle(gchopStick[i]); //关闭互斥体句柄
return (msg.wParam);
}
《内存管理》实验指导书
【实验内容】
设计一个虚拟存储区和内存工作区,并使用下列算法计算访问命中率。
(1) 进先出的算法(FIFO)
(2) 最近最少使用的算法(LRU)
(3) 最佳淘汰算法(OPT)
命中率=(1-页面失效次数)/页地址流长度
【实验要求】
1、 理解FIFO,LRU算法原理,理解参考程序的原理和实现思路。
2、 完成程序的设计,重点完成FIFO,LRU算法
3、 分析运算结果,在分配不同的物理块情况下,各算法的缺页情况有什么规律?
4、 完成OPT算法
【程序设计指导】
本实验的程序设计基本上按照实验内容进行。即首先用srand()和rand()函数定义和产生指令序列,然后将指令序列变换成相应的页地址流,并针对不同的算法计算出相应的命中率。实验中我们产生320条指令,每个虚拟页存放10条指令。进程分配的物理块从4变化到32。
【重要变量、结构和函数的建议】
(1)页面类型
typedef struct
{
int pn;
int pfn;
int counter;
int time
} pl-type;
其中pn 为页号,pfn为面号, counter为一个周期内访问该页面的次数, time为访问时间。
(2) 页面控制结构
pfc_struct
{
int pn,pfn;
struct pfc_struct *next;
}
typedef struct pfc_struct pfc_type;
pfc_type pfc_struct[total_vp], *freepf_head, *busypf_head;
pfc_type *busypf_tail;
其中:
pfc[total_vp]定义用户进程虚页控制结构。
*freepf_head为空页面头的指针。
*busypf_head为忙页面头的指针。
*busypf_tail为忙页面尾的指针。
(3)函数定义
void initialize( ):初始化函数,给每个相关的页面赋值。
void FIFO( ):计算使用FIFO算法时的命中率。
void LRU( ):计算使用LRU算法时的命中率。
(4)变量定义
int a[total_instruction]: 指令流数据组。
int page[total_instruction]: 每条指令所属的页号。
int offset[total_instruction]: 每页装入10条指令后取模运算页号偏移值。
int total_pf: 用户进程的内存页面数。
int disaffect: 页面失效次数。
【参考资料】
// Store.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <process.h>
#define TRUE 1
#define FALSE 0
#define INVALID -1
#define NULL 0
#define NUMBER_OF_INSTRUCTION 320 //指令流的指令条数
#define NUMBER_OF_VP 32 //进程的虚页页数
//#define LINEAR_ADDRESS
typedef struct
{
int no_of_vp; //虚拟页号
int no_of_pp; //物理页号
int counter_in_period; //一周期内访问的次数
int time; //访问时间
}vp_struct; //页面类型
vp_struct vp_array[NUMBER_OF_VP]; //页面结构数组
struct pp_struct //物理页面结构
{
int no_of_vp;
int no_of_pp;
struct pp_struct *next;
};
typedef struct pp_struct pp_type;
pp_type pp_control[NUMBER_OF_VP],*free_pp_head,*busy_pp_head,*busy_pp_tail;
int counter_page_default;
int address_of_instruction[NUMBER_OF_INSTRUCTION];
int page_of_instruction[NUMBER_OF_INSTRUCTION],offset_of_instruction[NUMBER_OF_INSTRUCTION];
int MAXINT=((1<<30)-1)*2+1; //2^31-1 2147483647
void initialize(int);
void FIFO(int); //先进先出
void LRU(int); //最近最久未使用页面淘汰算法(least recently used)
int main()
{
int S,i;
srand( (int)getpid() );
S=(int)rand() % 320;
#ifndef LINEAR_ADDRESS
for(i=0;i<NUMBER_OF_INSTRUCTION;i+=1) /*产生指令队列*/
{
address_of_instruction[i]=S; /*任选一指令访问点*/
address_of_instruction[i+1]=address_of_instruction[i]+1; /*顺序执行一条指令*/
address_of_instruction[i+2]=(int)rand()%320; /*执行前地址指令m'*/
address_of_instruction[i+3]=address_of_instruction[i+2]+1; /*执行后地址指令*/
S=(int)rand()%320;
}
#else
for(i=0;i<NUMBER_OF_INSTRUCTION;i+=1) /*产生指令队列*/
{
address_of_instruction[i]=i;
}
#endif
for(i=0;i<NUMBER_OF_INSTRUCTION;i++) /*将指令序列变换成页地址流*/
{
page_of_instruction[i]=address_of_instruction[i]/10;
offset_of_instruction[i]=address_of_instruction[i]%10;
}
for(i=4;i<=32;i++) /*用户内存工作区从个页面到个页面*/
{
printf("%2d 物理块:",i);
FIFO(i);
LRU(i);
printf("/n");
}
return 0;
}
void FIFO(int total_pf)
{
int i,j;
pp_type *p,*t;
initialize(total_pf);
busy_pp_head=busy_pp_tail=NULL;
for(i=0;i<NUMBER_OF_INSTRUCTION;i++)
{
if(vp_array[page_of_instruction[i]].no_of_pp==INVALID)
{
counter_page_default+=1;
if(free_pp_head==NULL)
{
p=busy_pp_head->next;
vp_array[busy_pp_head->no_of_vp].no_of_pp=INVALID;
free_pp_head=busy_pp_head;
free_pp_head->next=NULL;
busy_pp_head=p;
}
p=free_pp_head->next;
free_pp_head->next=NULL;
free_pp_head->no_of_vp=page_of_instruction[i];
vp_array[page_of_instruction[i]].no_of_pp=free_pp_head->no_of_pp;
if(busy_pp_tail==NULL)
busy_pp_head=busy_pp_tail=free_pp_head;
else
{
busy_pp_tail->next=free_pp_head;
busy_pp_tail=free_pp_head;
}
free_pp_head=p;
}
}
printf("FIFO命中率:%6.4f ",1-(float)counter_page_default/320);
return;
}
void LRU(int total_pf)
{
int min,minj,i,j,present_time;//访问时刻
initialize(total_pf);
present_time=0;
for(i=0;i<NUMBER_OF_INSTRUCTION;i++)
{
if(vp_array[page_of_instruction[i]].no_of_pp==INVALID)
{
counter_page_default++;
if(free_pp_head==NULL) //无空闲页面
{
min=MAXINT;
for(j=0;j<NUMBER_OF_VP;j++)
if(min>vp_array[j].time&&vp_array[j].no_of_pp!=INVALID)
{
min=vp_array[j].time;minj=j;
}
free_pp_head=&pp_control[vp_array[minj].no_of_pp];
vp_array[minj].no_of_pp=INVALID;
vp_array[minj].time=-1;
free_pp_head->next=NULL;
}
vp_array[page_of_instruction[i]].no_of_pp=free_pp_head->no_of_pp;
vp_array[page_of_instruction[i]].time=present_time;
free_pp_head=free_pp_head->next;
}
else
vp_array[page_of_instruction[i]].time=present_time;// 使用
present_time++;
}
printf("LRU命中率:%6.4f ",1-(float)counter_page_default/320);
return ;
}
void initialize(int total_pf)
{
int i;
counter_page_default=0;
for(i=0;i<NUMBER_OF_VP;i++)
{
vp_array[i].no_of_vp=i;
vp_array[i].no_of_pp=INVALID;
vp_array[i].counter_in_period=0;
vp_array[i].time=-1;
}
for(i=1;i<total_pf;i++)
{
pp_control[i-1].next=&pp_control[i]; //建立pp_control[i-1]和ptf[i]之间的链接
pp_control[i-1].no_of_pp=i-1;
}
pp_control[total_pf-1].next=NULL;
pp_control[total_pf-1].no_of_pp=total_pf-1;
free_pp_head=&pp_control[0];
return;
}
《进(线)程管理》实验指导书
【实验目的】
1. 理解P-V操作的原理;
2. 理解WINDOWS下进程/线程的互斥和同步的实现机制;
【实验要求】
1. 在WINDOWS系统中实现生产者和消费者同步和互斥的P-V操作。
【实验内容】
1. 编写和编译一个WIN32控制台应用程序,模拟实现生产者和消费者的同步和互斥问题。
2. 使用文件的方式记录每一个产品(数据)的生产和消费的详细过程,以便事后研究。
【实验背景】
1. 生产者-消费者问题的描述
若干个生产者和消费者共同存取有限大小的缓冲区。存取规则如下:1.生产者或消费者每个时刻只能有1个进程生产或消费1个产品;2.不能向满缓冲区放产品;不能向空缓冲区取产品。
2. WINDOWS下进程的同步和互斥有关函数
2.1 互斥对象(Mutex)
就是互斥信号量,在一个时刻只能被一个线程使用。相关API包括:CreateMutex、OpenMutex和ReleaseMutex。 CreateMutex创建互斥对象,返回对象句柄;OpenMutex 打开并返回一个已存在的互斥对象句柄,用于后续访问;ReleaseMutex释放对互斥对象的占用,使之成为可用。
2.2 信号量对象(Semaphore)
就是资源信号量,初始值的取值范围在0到指定最大值之间,用于限制并发访问的线程数。相关API包括:CreateSemaphore、OpenSemaphore和ReleaseSemaphore。CreateSemaphore 创建一个信号量对象,在输入参数中指定初值和最大值,返回对象句柄。OpenSemaphore 打开并返回一个已存在的信号量对象句柄,用于后续访问。ReleaseSemaphore释放对信号量对象的占用,使之成为可用。
【实验步骤】
1. 在生产者-消费者问题中,假设缓冲区的大小为5,生产者个数为1,消费者个数为2。
2. 使用VC++6.0创建一个WIN32控制台应用程序,使用WINDOWS进程/线程相关函数解决生产者-消费者PV问题。
3. 可能用到的主要全局变量和函数提供如下参考和定义:
/*************************************************************
* 文件名:Producer_Consumer.cpp
* 创建日期:.10.5
* 作 者:苏曙光
* 使用者:软件工程级,操作系统实验用
* 功 能:用P-V操作解决生产者-消费者问题(windows版本)
* 描 述:) 1个生产者,个消费者
* 2) 缓冲区大小:
* 3) 互斥对象:csArray
* 信号量:hFull
* 信号量:hEmpty
*
*
**************************************************************/
#include "stdafx.h"
#include "stdio.h"
#include <windows.h>
#define FILE_LOG
#ifdef FILE_LOG
FILE * cfileLog;
#endif
//缓冲区,大小为
int array[5];
//记录生成数据的个数
int pointer;
//记录取得的数据的位置
int pointerget;
//用来保存数据和
int sum;
//临界区对象
CRITICAL_SECTION csArray;
//句柄,保存Full信号量
HANDLE hFull;
//句柄,保存Empty信号量
HANDLE hEmpty;
//生产者函数
DWORD WINAPI Producer(LPVOID lpParam)
{
int i = 0;
pointer = 0;
while( i < 100 )
{
WaitForSingleObject(hEmpty,INFINITE);
EnterCriticalSection( &csArray);
array[(pointer++)%5] = i + 1;
printf("new data: %5d/n",i + 1);
#ifdef FILE_LOG
char DebugString[100];
int StringLong;
sprintf(DebugString,"new data: %5d/n",i + 1);
StringLong = strlen(DebugString);
fwrite(DebugString,1,StringLong,cfileLog);
#endif
LeaveCriticalSection( &csArray);
ReleaseSemaphore(hFull,1,NULL);
i++;
}
return 0;
}
//消费者函数A
DWORD WINAPI ConsumerA(LPVOID lpParam)
{
while(1)
{
WaitForSingleObject(hFull,INFINITE);
EnterCriticalSection( &csArray);
sum += array[(pointerget ++ )%5];
printf(" Consumer A get %5d/n",array[(pointerget -1)%5]);
if(pointerget == 100)
printf("The sum is %d",sum);
#ifdef FILE_LOG
char DebugString[100];
int StringLong;
sprintf(DebugString," Consumer A get %5d/n",array[(pointerget -1)%5]);
StringLong = strlen(DebugString);
fwrite(DebugString,1,StringLong,cfileLog);
#endif
LeaveCriticalSection( &csArray);
ReleaseSemaphore(hEmpty,1,NULL);
}
return 0;
}
//消费者函数B
DWORD WINAPI ConsumerB(LPVOID lpParam)
{
while(1)
{
WaitForSingleObject(hFull,INFINITE);
EnterCriticalSection( &csArray);
sum += array[(pointerget ++ )%5];
printf(" Consumer B get %5d /n",array[(pointerget -1 )%5]);
if(pointerget == 100)
printf("The sum is %d",sum);
#ifdef FILE_LOG
char DebugString[100];
int StringLong;
sprintf(DebugString," Consumer B get %5d /n",array[(pointerget -1 )%5]);
StringLong = strlen(DebugString);
fwrite(DebugString,1,StringLong,cfileLog);
#endif
LeaveCriticalSection( &csArray);
ReleaseSemaphore(hEmpty,1,NULL);
}
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThreadProducer,hThreadConsumerA,hThreadComsumerB;
sum = 0;
pointerget = 0;
#ifdef FILE_LOG
cfileLog = fopen("生产者_消费者日志.txt","w");
#endif
InitializeCriticalSection( &csArray);
hFull = CreateSemaphore(NULL, 0, 5, NULL);
hEmpty = CreateSemaphore(NULL, 5, 5, NULL);
hThreadProducer = CreateThread(NULL, 0, Producer, NULL, 0, NULL);
hThreadConsumerA = CreateThread(NULL, 0, ConsumerA, NULL, 0, NULL);
hThreadComsumerB = CreateThread(NULL, 0, ConsumerB, NULL, 0, NULL);
getchar();
fclose(cfileLog);
return 0;
}