2020-10-29 实验四 进程同步与通信

这篇博客详细介绍了Windows环境下进行进程同步与通信的实验,包括使用临界区和信号量模拟售票、退票功能,实现生产者-消费者模型,以及通过命名管道和文件映射进行进程间通信。实验涵盖了VC6.0环境下的多线程并发执行机制和API应用,强调了同步互斥的重要性,并提供了丰富的代码示例和运行结果分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实验目的:

1. 掌握基本的同步与互斥算法,理解P,V操作。
2. 理解生产者消费者模型,了解其它典型的同步互斥模型,如哲学家就餐、读者-写者模型等。
3. 学习使用Windows中基本的同步对象,掌握相关API的使用方法。
4. 了解Windows中多线程的并发执行机制,实现进程的同步与互斥。
5. Windows进程间通信的方法有很多,了解其中的典型类型,如命名管道、文件映射等,掌握进程间通信的基本原理。了解windows系统环境下的进程通信机制,熟悉windows系统提供的进程通信API。

二、实验环境:

VC6.0

三、实验内容:

(写出主要的内容)
PART 1 进程同步与互斥
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;

        }

        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 : "<<--tickets<<endl;

               

        }

        else

                break;

        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;

               

        }

        else

                break;

        LeaveCriticalSection(&critical_sec);
//离开代码关键区域

 }    

 return 0;

}

运行截图:
2

2.使用信号量对象模拟售票功能。
(1)运行截图:
3

(2) 将函数Thread_B中的语句Sleep(10);改为Sleep(20);,再分析程序运行结果。
运行截图:
4
分析:运行两次thread_A后再运行一次thread_B。

3 . 简单的生产者-消费者问题

(1)运行截图:
5

(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;</
1. 目的: 调试、修改、运行模拟程序,通过形象化的状态显示,使学生理解进程的概念,了解同步通信的过程,掌握进程通信同步的机制,特别是利用缓冲区进行同步通信的过程。通过补充新功能,使学生能灵活运用相关知识,培养创新能力。 2. 内容及要求: 1) 调试、运行模拟程序。 2) 发现并修改程序中不完善的地方。 3) 修改程序,使用随机数控制创建生产者消费者的过程。 4) 在原来程序的基础上,加入缓冲区的写互斥控制功能,模拟多个进程存取一个公共缓冲区,当有进程正在写缓冲区时,其他要访问该缓冲区的进程必须等待,当有进程正在读取缓冲区时,其他要求读取的进程可以访问,而要求写的进程应该等待。 5) 完成1)、2)、3)功能的,得基本分,完成4)功能的加2分,有其它功能改进的再加2分 3. 程序说明:   本程序是模拟两个进程,生产者(producer)消费者(Consumer)工作。生产者每次产生一个数据,送入缓冲区中。消费者每次从缓冲区中取走一个数据。缓冲区可以容纳8个数据。因为缓冲区是有限的,因此当其满了时生产者进程应该等待,而空时,消费者进程应该等待;当生产者向缓冲区放入了一个数据,应唤醒正在等待的消费者进程,同样,当消费者取走一个数据后,应唤醒正在等待的生产者进程。就是生产者消费者之间的同步。   每次写入读出数据时,都将读写指针加一。当读写指针同样时,又一起退回起点。当写指针指向最后时,生产者就等待。当读指针为零时,再次要读取的消费者也应该等待。 为简单起见,每次产生的数据为0-99的整数,从0开始,顺序递增。两个进程的调度是通过运行者使用键盘来实现的。 4. 程序使用的数据结构 进程控制块:包括进程名,进程状态执行次数。 缓冲区:一个整数数组。 缓冲区说明块:包括类型,读指针,写指针,读等待指针写等待指针。 5. 程序使用说明   启动程序后,如果使用'p'键则运行一次生产者进程,使用'c'键则运行一次消费者进程。通过屏幕可以观察到两个进程的状态缓冲区变化的情况。
(1)进程的软中断通信 #include #include #include #include int wait_flag; void stop(); main( ) { int pid1, pid2; // 定义两个进程号变量 signal(2,stop); // 或者 signal (14,stop); while((pid1 = fork( )) == -1); // 若创建子进程1不成功,则空循环 if(pid1 > 0) { // 子进程创建成功,pid1为进程号 while((pid2 = fork( )) == -1); // 创建子进程2 if(pid2 > 0) { wait_flag = 1; //sleep(1); // 父进程等待5秒 kill(pid1,SIGUSR1); // 杀死进程1 kill(pid2,SIGUSR2); // 杀死进程2 wait(0); wait(0); printf("\n Parent process is killed !!\n"); exit(0); // 父进程结束 } else { wait_flag = 1; signal(SIGUSR2,stop); // 等待进程2被杀死的中断号17 printf("\n Child process 2 is killed by parent !!\n"); exit(0); } } else { wait_flag = 1; signal(SIGUSR1,stop); // 等待进程1被杀死的中断号16 printf("\n Child process 1 is killed by parent !!\n"); exit(0); } } void stop() { wait_flag = 0; } (2)进程的管道通信 #include #include #include int pid1,pid2; // 定义两个进程变量 main( ) { int fd[2]; char OutPipe[100],InPipe[100]; // 定义两个字符数组 pipe(fd); // 创建管道 while((pid1 = fork( )) == -1); // 如果进程1创建不成功,则空循环 if(pid1 == 0) { lockf(fd[1],1,0); // 锁定管道 sprintf(OutPipe,"\n Child process 1 is sending message!\n"); write(fd[1],OutPipe,50); // 向管道写入数据 sleep(5); // 等待读进程读出数据 lockf(fd[1],0,0); // 解除管道的锁定 exit(0); // 结束进程1 } else { while((pid2 = fork()) == -1); // 若进程2创建不成功,则空循环 if(pid2 == 0) { lockf(fd[1],1,0); sprintf(OutPipe,"\n Child process 2 is sending message!\n"); write(fd[1],OutPipe,50); sleep(5); lockf(fd[1],0,0); exit(0); } else { wait(0); // 等待子进程1 结束 read(fd[0],InPipe,50); // 从管道中读出数据 printf("%s\n",InPipe); // 显示读出的数据 wait(0); // 等待子进程2 结束 read(fd[0],InPipe,50); printf("%s\n",InPipe); exit(0); // 父进程结束 } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值