实验四 进程同步与通信

  • 一、实验目的:
  • 二、实验环境:
  • 三、实验内容:
  • 四、心得体会:

一、实验目的:

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. 【操作系统】实验四 进程同步与通信

    目录 一.生产者消费者问题 代码1: 运行结果: 二.进程间的通信--软中断实现 代码2: 输出结果: 参考资料: 一.生产者消费者问题 代码1: 因为Linux系统中gcc编译环境下会发生内置函数找 ...

  2. 实验四 进程同步与通信(一)进程同步与互斥1

    一.实验目的 1.掌握基本的同步与互斥算法,理解P,V操作. 2.理解生产者消费者模型,了解其它典型的同步互斥模型,如哲学家就餐.读者-写者模型等. 3.学习使用Windows中基本的同步对象,掌握相 ...

  3. 前仿真和后仿真的区别,按键消抖设计思想、PLL使用、ODDR2的原语使用 --2020/10/29工作总结

    2020/10/29工作总结 前仿真和后仿真的区别 前仿真 综合后仿真 后仿真 synthesize和implement.generate bitstream 参考链接 按键消抖设计思想 PLL使用 ...

  4. 山东大学 2020级数据库系统 实验四

    What's more 山东大学 2020级数据库系统 实验一 山东大学 2020级数据库系统 实验二 山东大学 2020级数据库系统 实验三 山东大学 2020级数据库系统 实验四 山东大学 202 ...

  5. 【不忘初心】Win10_20H2_2009_19042.572_X64_六合一_[纯净精简版](2020.10.29)

    母版来自MSDN  WIN10_20H2.19042.508,集成补到19041.572,20H2相比1909 2004版本要稳定很多,精简起来也比较顺手,相对来说体积比之前的要小一些,精简方法基本上 ...

  6. 2020.10.29腾讯QQ音乐社招前端电话一面总结

    2020.10.29腾讯QQ音乐社招前端电话一面总结 面试官晚上19:16打过来的,聊了44分钟,到八点准时结束.无论过没过,都记录一下面试过程吧,是问了几个大问题,在几个大问题的基础上根据你的回答, ...

  7. 第三轮测试卷一(2020.10.29)

    第三轮测试卷一(2020.10.29) 铺石板,输入n x m的广场,和a x a的石板,求最少需要多少石板? /* 算法思想:没啥.... 理解向上取整就行 */num=((n+a-1)/a)*(( ...

  8. 操作系统实验四 进程同步与互斥

    一.实验目的: 掌握基本的同步与互斥算法,理解P,V操作. 理解生产者消费者模型,了解其它典型的同步互斥模型,如哲学家就餐.读者-写者模型等. 了解LINUX中进程同步互斥的实现方法,掌握相关函数的使 ...

  9. 【2020.10.29 洛谷团队赛 普及组】T2 U138014 魔法药水

    题目描述 小武的实验室里有一种魔法药水,这个药水有个很奇怪的性质,它只能在盛放的体积为2的幂次时保 持稳定,例如1,2,4,81,2,4,81,2,4,8.所以小武在实验室里放置了很多容积为2的幂次的 ...

最新文章

  1. 彻底理解HashMap及LinkedHashMap
  2. 转:项目报告应该汇报什么内容?
  3. 位bit、字节byte、kb、mb
  4. 远程连接Windows服务器
  5. xmodmap: unable to open display '' Error: Couldn't connect to XServer passing null display
  6. gcc版本降级/升级
  7. Spring Schedule定时关单快速入门
  8. IDA Pro7.0 使用技巧 总结
  9. 一句公道话引发的......
  10. java BitSet2
  11. Xcode12 “PushKit apps that use VoIP push must link either CallKit or IncomingCallNotifications
  12. pandasSeries模块
  13. tomcat修改端口号失效
  14. CSR系列开发板的编程器/烧写器
  15. JAVA设计模式之策略模式
  16. DNS主域名服务器、从域名服务器和缓存域名服务器的构建和原理
  17. excel查重复_毕业季论文查重攻略,手把手教你降低重复率!
  18. pdf怎么压缩文件到最小?如何将pdf压缩到指定大小?压缩pdf文件大小怎么压缩?如何压缩pdf大小?
  19. 【使用指南】Excel筛选包含指定文本所在的整行
  20. WubaRN hermes调研-基于混合工程的改造方案

热门文章

  1. 应用ceph对象存储(ceph-13.2.10)
  2. 全链路压测需要如何开展?
  3. 手动搭建高可用的Redis5.0分片集群,从理论到实践,超详细
  4. STM32F103单片机驱动TM1637数码管显示模块
  5. AndroidStudio更改SDK路径以及AVD模拟器路径
  6. “(535, b‘Error: authentication failed‘)“身份验证失败问题
  7. 2021年网络系统管理网络模块show
  8. 孩子长高应该吃什么呢?
  9. Linux 修复硬盘smart,使用 Smartmontools 检测硬盘坏道
  10. 关于uC/OS-II 概述