2020-10-29 实验四 进程同步与通信
实验四 进程同步与通信
- 一、实验目的:
- 二、实验环境:
- 三、实验内容:
- 四、心得体会:
一、实验目的:
1. 掌握基本的同步与互斥算法,理解P,V操作。
2. 理解生产者消费者模型,了解其它典型的同步互斥模型,如哲学家就餐、读者-写者模型等。
3. 学习使用Windows中基本的同步对象,掌握相关API的使用方法。
4. 了解Windows中多线程的并发执行机制,实现进程的同步与互斥。
5. Windows进程间通信的方法有很多,了解其中的典型类型,如命名管道、文件映射等,掌握进程间通信的基本原理。了解windows系统环境下的进程通信机制,熟悉windows系统提供的进程通信API。
二、实验环境:
VC6.0
三、实验内容:
(写出主要的内容)
PART 1 进程同步与互斥
1.使用临界区对象,模拟售票功能。
(1) 运行截图
(2) 在分析程序运行结果的基础上,增加一个函数,模拟退票功能,并在主函数中加入适当的语句。
代码:
#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI SellPro_1(
LPVOID lpParameter);DWORD WINAPI SellPro_2(
LPVOID lpParameter );DWORD WINAPI SellPro_3(
LPVOID lpParameter );int tickets=100;CRITICAL_SECTION critical_sec; //定义关键区域void main(){HANDLE hThread1;HANDLE hThread2;HANDLE hThread3;InitializeCriticalSection(&critical_sec); //初始化关键区域hThread1=CreateThread(NULL,0,SellPro_1,NULL,0,NULL);hThread2=CreateThread(NULL,0,SellPro_2,NULL,0,NULL);hThread3=CreateThread(NULL,0,SellPro_3,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);CloseHandle(hThread3);Sleep(4000);}DWORD WINAPI SellPro_1(
LPVOID lpParameter ){ while(TRUE){ Sleep(1);EnterCriticalSection(&critical_sec);
//进入关键代码区域 if(tickets>0){cout<<"thread1 sell
ticket : "<<--tickets<<endl;}elsebreak;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 : "<<--tickets<<endl;}elsebreak;LeaveCriticalSection(&critical_sec);
//离开代码关键区域} return 0;}DWORD WINAPI SellPro_3(
LPVOID lpParameter){ while(TRUE){ Sleep(3);EnterCriticalSection(&critical_sec);
//进入关键代码区域 if(tickets>0){cout<<"\treturn ticket :
"<<++tickets<<endl;}elsebreak;LeaveCriticalSection(&critical_sec);
//离开代码关键区域} return 0;}
运行截图:
2.使用信号量对象模拟售票功能。
(1)运行截图:
(2) 将函数Thread_B中的语句Sleep(10);改为Sleep(20);,再分析程序运行结果。
运行截图:
分析:运行两次thread_A后再运行一次thread_B。
3 . 简单的生产者-消费者问题
(1)运行截图:
(2)修改程序,将每次产生的数据改为一个100之内的随机数。
修改的代码:
#include <stdio.h>#include <process.h>#include <windows.h>#include<stdlib.h>#include<time.h>int END_PRODUCE_NUMBER=1;int g_Buffer;CRITICAL_SECTION g_cs;HANDLE g_hEventBufferEmpty,g_hEventBufferFull;unsigned int __stdcall ProducerThreadFun(PVOID pM) //生产者进程{int i;srand((unsigned int)time(NULL));for (;;){i=rand()%100;WaitForSingleObject(g_hEventBufferEmpty,INFINITE);EnterCriticalSection(&g_cs);g_Buffer=i;printf("生产者将数据%d放入缓冲区\n",i);LeaveCriticalSection(&g_cs);SetEvent(g_hEventBufferFull);Sleep(1000);END_PRODUCE_NUMBER ++;if(END_PRODUCE_NUMBER==10)break;}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);if(END_PRODUCE_NUMBER==10)break;}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;}
运行截图:
(3)修改程序,生产者进程中产生数据的个数不固定为20,如果无键盘输入事件,则一直循环产生数据,直到有键盘按下的操作才停止。相应的消费者进程中语句也需要修改。
提示:可使用kbhit( )函数判断有无键盘输入。
修改的代码:
#include <stdio.h>#include <process.h>#include <windows.h>#include<stdlib.h>#include<time.h>#include<conio.h>int END_PRODUCE_NUMBER=1;int g_Buffer;CRITICAL_SECTION g_cs;HANDLE g_hEventBufferEmpty,g_hEventBufferFull;unsigned int __stdcall ProducerThreadFun(PVOID pM) //生产者进程{int i;srand((unsigned int)time(NULL));while(!kbhit(
)){i=rand()%100;WaitForSingleObject(g_hEventBufferEmpty,INFINITE);EnterCriticalSection(&g_cs);g_Buffer=i;printf("生产者将数据%d放入缓冲区\n",i);LeaveCriticalSection(&g_cs);SetEvent(g_hEventBufferFull);Sleep(1000);END_PRODUCE_NUMBER ++;}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;}
运行截图:
4.在理解简单生产者-消费者程序的基础上,自己编程实现稍复杂的模型,将缓冲区改为能够存放若干个整数的数组,如int
g_Buffer[N]; 其中N为一个整型常量。一个生产者,两个消费者。算法流程参考教材。
代码:
#include <stdio.h>#include <process.h>#include <windows.h>#include<conio.h>const int END_PRODUCE_NUMBER=20;int g_Buffer[100];CRITICAL_SECTION g_cs;HANDLE g_hEventBufferEmpty,g_hEventBufferFull;unsigned int __stdcall ProducerThreadFun(PVOID pM) //生产者进程{int i=1;while(!kbhit()){WaitForSingleObject(g_hEventBufferEmpty,INFINITE);EnterCriticalSection(&g_cs);g_Buffer[i]=i;printf("生产者将数据%d放入缓冲区\n",i);g_Buffer[++i]=i;printf("生产者将数据%d放入缓冲区\n",i);LeaveCriticalSection(&g_cs);SetEvent(g_hEventBufferFull);Sleep(1000);i++;}return 0;}unsigned int __stdcall ConsumerThreadFun(PVOID pM) //消费者进程{int flag=1;while(flag) {static int i=1;WaitForSingleObject(g_hEventBufferFull,INFINITE);EnterCriticalSection(&g_cs); printf("消费者从缓冲区中取出数据%d\n",i);if(g_Buffer[i]==END_PRODUCE_NUMBER)flag=0;LeaveCriticalSection(&g_cs);SetEvent(g_hEventBufferEmpty);Sleep(1000);i++;}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;}
运行截图:
PART 2 进程通信
共享内存文件映射方式
(1)运行截图:
(2)实现上述程序的控制停止功能,可以两种方式停止发送字符串:一种是服务器端发送10个字符串后便结束程序;另一种是用户在服务器端输入字符即结束程序。
修改的代码:
#include <iostream>#include <windows.h>#include <stdlib.h>#include <time.h>#include <conio.h>using namespace std;int main(int argc, char *argv[]){int nRetCode = 0;char szBuffer[20] ;char c[20];HANDLE hMapping = CreateFileMapping(NULL,NULL,PAGE_READWRITE,0,4096,
"ShareMemory");LPVOID lpBase =
MapViewOfFile(hMapping,FILE_MAP_WRITE|FILE_MAP_READ,0,0,0);srand((unsigned)time(NULL));while(1){ for(int i=0;i<=18;i++)szBuffer[i]=rand()%26+65;szBuffer[19]='\0';puts(szBuffer);strcpy((char*)lpBase,szBuffer);Sleep(1000);if(kbhit()){gets(c);if(strlen(c)==10)break;}}Sleep(20000);UnmapViewOfFile(lpBase);CloseHandle(hMapping);return nRetCode;}
运行截图:
(3)将上述程序的功能改为: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] ;HANDLE hMapping =
CreateFileMapping(NULL,NULL,PAGE_READWRITE,0,4096, "ShareMemory");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]);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;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;}
运行截图:
四、心得体会:
通过这节实验课,我懂得了关于基本的同步和互斥算法。理解到了很多关于p,v的操作,学会了使用Windows中基本的同步对象。掌握了Windows中的多线程的并发执行机制,可以实现进程之间的同步。了解到了Windows系统下的进程通信机制和进程通信API。
2020-10-29 实验四 进程同步与通信相关推荐
- 【操作系统】实验四 进程同步与通信
目录 一.生产者消费者问题 代码1: 运行结果: 二.进程间的通信--软中断实现 代码2: 输出结果: 参考资料: 一.生产者消费者问题 代码1: 因为Linux系统中gcc编译环境下会发生内置函数找 ...
- 实验四 进程同步与通信(一)进程同步与互斥1
一.实验目的 1.掌握基本的同步与互斥算法,理解P,V操作. 2.理解生产者消费者模型,了解其它典型的同步互斥模型,如哲学家就餐.读者-写者模型等. 3.学习使用Windows中基本的同步对象,掌握相 ...
- 前仿真和后仿真的区别,按键消抖设计思想、PLL使用、ODDR2的原语使用 --2020/10/29工作总结
2020/10/29工作总结 前仿真和后仿真的区别 前仿真 综合后仿真 后仿真 synthesize和implement.generate bitstream 参考链接 按键消抖设计思想 PLL使用 ...
- 山东大学 2020级数据库系统 实验四
What's more 山东大学 2020级数据库系统 实验一 山东大学 2020级数据库系统 实验二 山东大学 2020级数据库系统 实验三 山东大学 2020级数据库系统 实验四 山东大学 202 ...
- 【不忘初心】Win10_20H2_2009_19042.572_X64_六合一_[纯净精简版](2020.10.29)
母版来自MSDN WIN10_20H2.19042.508,集成补到19041.572,20H2相比1909 2004版本要稳定很多,精简起来也比较顺手,相对来说体积比之前的要小一些,精简方法基本上 ...
- 2020.10.29腾讯QQ音乐社招前端电话一面总结
2020.10.29腾讯QQ音乐社招前端电话一面总结 面试官晚上19:16打过来的,聊了44分钟,到八点准时结束.无论过没过,都记录一下面试过程吧,是问了几个大问题,在几个大问题的基础上根据你的回答, ...
- 第三轮测试卷一(2020.10.29)
第三轮测试卷一(2020.10.29) 铺石板,输入n x m的广场,和a x a的石板,求最少需要多少石板? /* 算法思想:没啥.... 理解向上取整就行 */num=((n+a-1)/a)*(( ...
- 操作系统实验四 进程同步与互斥
一.实验目的: 掌握基本的同步与互斥算法,理解P,V操作. 理解生产者消费者模型,了解其它典型的同步互斥模型,如哲学家就餐.读者-写者模型等. 了解LINUX中进程同步互斥的实现方法,掌握相关函数的使 ...
- 【2020.10.29 洛谷团队赛 普及组】T2 U138014 魔法药水
题目描述 小武的实验室里有一种魔法药水,这个药水有个很奇怪的性质,它只能在盛放的体积为2的幂次时保 持稳定,例如1,2,4,81,2,4,81,2,4,8.所以小武在实验室里放置了很多容积为2的幂次的 ...
最新文章
- 彻底理解HashMap及LinkedHashMap
- 转:项目报告应该汇报什么内容?
- 位bit、字节byte、kb、mb
- 远程连接Windows服务器
- xmodmap: unable to open display '' Error: Couldn't connect to XServer passing null display
- gcc版本降级/升级
- Spring Schedule定时关单快速入门
- IDA Pro7.0 使用技巧 总结
- 一句公道话引发的......
- java BitSet2
- Xcode12 “PushKit apps that use VoIP push must link either CallKit or IncomingCallNotifications
- pandasSeries模块
- tomcat修改端口号失效
- CSR系列开发板的编程器/烧写器
- JAVA设计模式之策略模式
- DNS主域名服务器、从域名服务器和缓存域名服务器的构建和原理
- excel查重复_毕业季论文查重攻略,手把手教你降低重复率!
- pdf怎么压缩文件到最小?如何将pdf压缩到指定大小?压缩pdf文件大小怎么压缩?如何压缩pdf大小?
- 【使用指南】Excel筛选包含指定文本所在的整行
- WubaRN hermes调研-基于混合工程的改造方案
热门文章
- 应用ceph对象存储(ceph-13.2.10)
- 全链路压测需要如何开展?
- 手动搭建高可用的Redis5.0分片集群,从理论到实践,超详细
- STM32F103单片机驱动TM1637数码管显示模块
- AndroidStudio更改SDK路径以及AVD模拟器路径
- “(535, b‘Error: authentication failed‘)“身份验证失败问题
- 2021年网络系统管理网络模块show
- 孩子长高应该吃什么呢?
- Linux 修复硬盘smart,使用 Smartmontools 检测硬盘坏道
- 关于uC/OS-II 概述