目录
实验二 进程同步与进程通信
一、实验目的
二、实验内容
任务一、进程同步与互斥
任务二、进程通信
实验二 进程同步与进程通信
备注:大二(下)操作系统实验二
一、实验目的
掌握基本的同步与互斥算法,理解P,V操作
学习使用Windows中基本的同步对象,掌握相关API的使用方法
了解Windows中多线程的并发执行机制,实现进程的同步与互斥
了解Wndows进程间通信方法的典型类型,如命名管道、文件映射等,掌握进程间通信的基本原理
了解windows系统环境下的进程通信机制,熟悉windows系统提供的进程通信API
二、实验内容
实验环境:DEV C++
任务一、进程同步与互斥
1、使用临界区对象模拟售票功能
其中SellPro_1, SellPro_2两个函数分别对应两个售票进程,一次售出一张票
#include <windows.h>
#include <iostream>
#define N 100
using namespace std;
DWORD WINAPI SellPro_1(LPVOID lpParameter);
DWORD WINAPI SellPro_2(LPVOID lpParameter );
DWORD WINAPI SellPro_3(LPVOID lpParameter );
int tickets = N;
CRITICAL_SECTION critical_sec;//定义关键区域
DWORD WINAPI SellPro_1(LPVOID lpParameter )
{
while(TRUE)
{
Sleep(1);
EnterCriticalSection( &critical_sec);
//进入关键区域
if(tickets>0)
{
cout<< "thread1 sell ticket, remain: "<<--tickets<<endl;
}
else break;
LeaveCriticalSection( &critical_sec);
//离开关键区域
}
return 0;
}
DWORD WINAPI SellPro_2(LPVOID lpParameter )
{
while(TRUE)
{
Sleep(1);
EnterCriticalSection( &critical_sec);
//进入关键区域
if(tickets>0)
{
cout<< "thread2 sell ticket, remain: "<<--tickets<<endl;
}
else break;
LeaveCriticalSection( &critical_sec);
//离开关键区域
}
return 0;
}
int main()
{
HANDLE hThread1;
HANDLE hThread2;
InitializeCriticalSection(&critical_sec);//初始化关健区域
hThread1 = CreateThread(NULL,0,SellPro_1,NULL,0,NULL);
hThread2 = CreateThread(NULL,0, SellPro_2,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);
return 0;
}
2、使用信号量对象模拟售票功能
其中SellPro_1, SellPro_2两个函数分别对应两个售票进程,一次售出一张票
#include <windows.h>
#include <iostream>
using namespace std;
static HANDLE g_hSemaphore = INVALID_HANDLE_VALUE;
static int g_Count = 100;
DWORD WINAPI Thread_A(LPVOID lpParamter);
DWORD WINAPI Thread_B(LPVOID lpParamter);
DWORD WINAPI Thread_A(LPVOID lpParamter)
{
long count;
while(1)
{
WaitForSingleObject(g_hSemaphore,INFINITE);
if(g_Count>0)
cout<<"thread_A sell ticket, remain: "<<--g_Count<<endl;
else break;
ReleaseSemaphore(g_hSemaphore,1,&count);
Sleep(10);
}
return 0;
}
DWORD WINAPI Thread_B(LPVOID lpParamter)
{
long count;
while(1)
{
WaitForSingleObject(g_hSemaphore,INFINITE);
if(g_Count>0)
cout<< "thread_B sell ticket, remain: "<<--g_Count<<endl;
else break;
ReleaseSemaphore(g_hSemaphore,1,&count);
Sleep(10);
}
return 0;
}
int main(int argc, char** argv)
{
HANDLE threadA = INVALID_HANDLE_VALUE;
HANDLE threadB = INVALID_HANDLE_VALUE;
g_hSemaphore = CreateSemaphore(NULL,1,20,TEXT( "semaphore"));
threadA = CreateThread(NULL,0,Thread_A,NULL,0,NULL);
threadB = CreateThread(NULL,0,Thread_B,NULL,0,NULL);
system("pause");
CloseHandle(threadA);
CloseHandle(threadB);
return 0;
}
3、简单的生产者--消费者问题
一个缓冲区,存放一个整型数据
#include <stdio.h>
#include <process.h>
#include <windows.h>
const int END_PRODUCE_NUMBER=20;
int g_Buffer;
CRITICAL_SECTION g_cs;
HANDLE g_hEventBufferEmpty, g_hEventBufferFull;
unsigned int __stdcall ProducerThreadFun(PVOID pM) //生产者进程
{
int i;
for (i=1;i<=END_PRODUCE_NUMBER;i++)
{
WaitForSingleObject(g_hEventBufferEmpty, INFINITE);
EnterCriticalSection(&g_cs);
g_Buffer=i;
printf("生产者将数据%d放入缓冲区\n",i);
LeaveCriticalSection(&g_cs);
SetEvent(g_hEventBufferFull);
Sleep (1000);
}
return 0;
}
unsigned int __stdcall ConsumerThreadFun(PVOID pM) //消费者进程
{
int flag=1;
while(flag)
{
WaitForSingleObject(g_hEventBufferFull, INFINITE);
EnterCriticalSection(&g_cs);
printf("消费者从缓冲区中取出数据%d\n", g_Buffer);
if(g_Buffer==END_PRODUCE_NUMBER) flag=0;
LeaveCriticalSection(&g_cs);
SetEvent(g_hEventBufferEmpty);
Sleep(1000);
}
return 0;
}
int main()
{
HANDLE hThread[2];
printf("生产者消费者问题\n");
InitializeCriticalSection(&g_cs);
g_hEventBufferEmpty=CreateEvent(NULL, FALSE, TRUE, NULL);
g_hEventBufferFull=CreateEvent(NULL, FALSE, FALSE, NULL);
hThread[0]=(HANDLE)_beginthreadex(NULL, 0, ProducerThreadFun, NULL, 0, NULL);
hThread[1]= (HANDLE)_beginthreadex(NULL, 0, ConsumerThreadFun, NULL, 0, NULL);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(g_hEventBufferEmpty);
CloseHandle(g_hEventBufferFull);
DeleteCriticalSection(&g_cs);
return 0;
}
任务二、进程通信
服务程序server端每次发送两个100之内的整数
客户程序client端实现将两个整数相加,并输出加法计算式
// Server端
#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
int main(int argc, char *argv[])
{
int nRetCode = 0;
char szBuffer[3] ;
system("color F0");
// 创建一个特定大小的文件映射对象,名称为"ShareMemory"
HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "ShareMemory" ); // 第一个参数也可以是NULL
// 将这个文件映射对象的文件视图映射到进程的地址空间
LPVOID lpBase =MapViewOfFile( hMapping,FILE_MAP_WRITE|FILE_MAP_READ,0,0,0);
srand((unsigned)time(NULL));
while(1)
{
szBuffer[0]=rand()%100;
szBuffer[1]=rand()%100;
szBuffer[2]='\0';
printf("%d\t%d\n",szBuffer[0],szBuffer[1]);
// 向视图中写入两个100之内的整数
strcpy( (char* )lpBase, szBuffer);
Sleep(1000) ;
}
Sleep(20000);
UnmapViewOfFile(lpBase);
CloseHandle(hMapping);
return nRetCode;
}
// Client端
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, char *argv[])
{
int nRetCode = 0;
system("color EA");
// 打开这个名称为"ShareMemory"的文件映射对象
HANDLE hMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, NULL , "ShareMemory" );
if (hMapping)
{
wprintf(L"%s \r\n",L"Success");
// 把相同的文件映射视图映射到自己的地址空间中
LPVOID lpBase =MapViewOfFile( hMapping,FILE_MAP_READ| FILE_MAP_WRITE,0,0,0);
char szBuffer[20] = {0};
while(1)
{
// 从视图中读取服务进程所写入的数据
strcpy (szBuffer, (char* )lpBase);
printf("%d+%d=%d \n", szBuffer[ 0] , szBuffer[1], szBuffer[0]+szBuffer[1]);
Sleep( 1000);
}
UnmapViewOfFile( lpBase);
CloseHandle(hMapping);
}
else wprintf(L"%s",L"OpenMapping Error" );
return nRetCode;
}