用多线程实现“生产者-消费者问题”(代码+实验报告)

来源:互联网 发布:网络谣言著名案例 编辑:程序博客网 时间:2024/05/04 05:25

 

用多线程实现“生产者-消费者问题”(代码+实验报告)

 

  1. #include <iostream>
  2. #include <stdlib.h>
  3. #include <STDIO.H>
  4. #include <windows.h>
  5. using namespace std;
  6. typedef int semaphore;                          /* 信号量是一种特殊的整型变量 */    
  7. const int SIZE_OF_BUFFER = 5 ;                                //缓冲区长度
  8. const unsigned short PRODUCERS_COUNT = 2;       //生产者的个数
  9. const unsigned short CONSUMERS_COUNT = 3;       //消费者的个数
  10. DWORD producers[PRODUCERS_COUNT] ; //生产者线程的标识符                      
  11. DWORD consumers[CONSUMERS_COUNT] ;//消费者线程的标识符
  12. const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT; //总的线程数
  13. /**
  14. *定义信号量
  15. */
  16. HANDLE mutex ;                               //互斥信号量 
  17. HANDLE full ;                             //表示放有产品的缓冲区数,其初值为0 
  18. HANDLE empty ;                            //表示可供使用的缓冲区数,其初值为N 
  19. /**
  20. *定义共享缓冲区
  21. */
  22. semaphore buffer[SIZE_OF_BUFFER]; 
  23. /**
  24. *定义生产者和消费者使用的指针 
  25. */
  26. int in = 0 ;
  27. int out = 0 ;
  28. int productNum = 0 ;
  29. DWORD WINAPI Producer(LPVOID) ;
  30. DWORD WINAPI Consumer(LPVOID) ;
  31. int main(int argc, char *argv[])
  32. {
  33.     //创建Mutex和Semaphore
  34.     mutex = CreateMutex(NULL,FALSE,NULL);
  35.     full = CreateSemaphore(NULL,0,SIZE_OF_BUFFER,NULL);
  36.     empty = CreateSemaphore(NULL,SIZE_OF_BUFFER,SIZE_OF_BUFFER,NULL);
  37.     
  38.     
  39.     HANDLE PVThreads[THREADS_COUNT];     //各线程的handle 
  40.     
  41.      //创建生产者线程
  42.      for (int i=0;i<PRODUCERS_COUNT;i++){
  43.           PVThreads[i] = CreateThread(NULL,0,Producer,NULL,0,&producers[i]);
  44.           if (PVThreads[i] == NULL) break;
  45.      }
  46.      //创建消费者线程 
  47.      for (int i=0;i<CONSUMERS_COUNT;i++){
  48.            PVThreads[PRODUCERS_COUNT+i]
  49.                 =CreateThread(NULL,0,Consumer,NULL,0,&consumers[i]);
  50.             if (PVThreads[i]==NULL) break;
  51.      }
  52.     
  53.     bool isContinue = true ;
  54.     while(isContinue)
  55.     { 
  56.           if(getchar()){  //按回车后终止程序运行
  57.                isContinue = false
  58.            }
  59.     }
  60.     system("PAUSE");    
  61.     return 0;
  62. }
  63. void enBuffer(int pos)
  64. {
  65.     cout<<"正在生产产品..."<<endl ;
  66.     Sleep(2000) ;
  67.     buffer[pos] = -1 ;
  68.     productNum++ ;
  69.     cout<<"生产完成!    已生产"<<productNum<<"个产品,并将新产品放在了缓冲区位置:"<<pos<<endl ;
  70. }
  71. void deBuffer(int pos)
  72. {
  73.     cout<<"正在消费产品..."<<endl ;
  74.     Sleep(1000) ;
  75.     buffer[pos] = -2 ;
  76.     productNum-- ;
  77.     cout<<"已消费在缓冲区位置:"<<pos<<"的产品,缓冲区剩余空间:"<<SIZE_OF_BUFFER-productNum<<endl ;
  78.     cout<<endl ; 
  79. }
  80. /**
  81. *生产者 
  82. */
  83. DWORD WINAPI Producer(LPVOID lpParam )
  84. {
  85.     while(1)
  86.     {
  87.         WaitForSingleObject(empty,INFINITE);  // P(empty) 生产者信号量 -1 
  88.         WaitForSingleObject(mutex,INFINITE);  // P(mutex) 获取线程间互斥信号 
  89.         enBuffer(in) ;
  90.         Sleep(1000) ;
  91.         in = (in+1)%SIZE_OF_BUFFER ;
  92.         ReleaseMutex(mutex);                  // V(mutex) 释放线程间互斥信号 
  93.         ReleaseSemaphore(full,1,NULL);        // V(full) 消费者信号量 +1 
  94.         
  95.     }
  96.     return 0;
  97. }
  98. /**
  99. *消费者 
  100. */
  101. DWORD WINAPI Consumer(LPVOID lpPara)
  102. {
  103.     while(1)
  104.     {
  105.         WaitForSingleObject(full,INFINITE)== WAIT_ABANDONED ;        //P(full) 消费者信号量-1 
  106.         WaitForSingleObject(mutex,INFINITE);       //P(mutex) 获得线程间互斥信号 
  107.         deBuffer(out) ;
  108.         Sleep(1000) ;
  109.         out = (out+1)%SIZE_OF_BUFFER ;
  110.         ReleaseMutex(mutex);                       //V(mutex) 释放线程间互斥信号 
  111.         ReleaseSemaphore(empty,1,NULL);            //V(empty) 生产者信号量+1 
  112.         
  113.     }
  114.     return 0;
  115. }

北航软件学院《一级实践》实验报告

学号:GS0821594  姓名:叶现                     第 11 周

内容

训练

用多线程实现“生产者-消费者问题”

 

解决该问题的思路

假设有一组(多个)生产者和一组(多个)消费者,生产者负责生产物品,然后将物品放置在一个缓冲区中供消费者消费。消费者从缓冲区取走物品。假定缓冲区共有N,不妨把它们设想成一个环形缓冲池。如下图所示:

 

中,阴影部分表示该缓冲区中放有的产品,否则为空。In表示生产者下次存入产品的单元;out表示消费者下次取出产品的单元。

1)       为使这两类进程协调工作,防止盲目的生产和消费,它们应满足如下同步条件:时刻所有生产者存放产品的单元数不能超过缓冲区的总容量(N)。

2)       所有消费者取出产品的总量不能超过所有生产者当前生产产品的总量。

设缓冲区的编号为0~N-1,inout分别是生产者进程和消费者进程使用的指针,指向下面可用的缓冲区,初值都是0

为使两类进程实行同步操作,应设置三个信号量:两个计数信号量fullempty,一个互斥信号量mutex

full:表示放有产品的缓冲区数,其初值为0

empty:表示可供使用的缓冲区数,其初值为N

mutex:互斥信号量,初值为1表示各进程互斥进入临界区,保证任何时候只有一个进程使用缓冲区。

下面是解决这个问题的算法描述。

生产者进程Producer

消费者进程Consumer

while(TRUE)

{

P(empty);

P(mutex)

产品送往bufferin);

in=(in+1)mod n

V(mutex);

V(full);

}

while(TRUE)

{

P(full);

P(mutex)

bufferout)中取出产品;

in=(in+1)mod n

V(mutex);

V(empty);

}

在生产者消费者问题中需满足下面三点:

1)       在每个程序中坐须先做P(mutex)后做V(mutex)二者要成对出现。夹在二者中间的代码段就是该进程的监界区。

2)       对同步信号量fullemptyPV操作同样必须成对出现,但它们分别位于不同的程序中。

3)       无论在生产者进程中还是在消费者进程中,两个P操作的次序不能颠倒:应先执行同 步信号量的P操作,然后执行互斥信号量的P操作。否则可能造成进程死锁。

本周开发源代码

代码的功能简述

用多线程实现“生产者-消费者问题”

开发的收获

关于Windows多线程API的使用;

深入了解了进程互斥问题

开发中碰到的主要困难

1)       关于Windows多线程API的使用:

2)       “生产者-消费者问题”问题的实现机制

 

开发中未能解决的问题

针对本周训练内容自己设计的案例

案例的主要功能

多线程实现“生产者-消费者问题”

用到的基本知识

进程同步与互斥原理;临界资源和临界区的相关定义;几种互斥的实现方式;关于信号量的使用及其实现方式

程序注意了哪些规范

代码格式、常量的定义、函数的声明

你进行了哪些测试

程序进行了哪些有效性检查

你是如何保证程序的高效率的

注意:实验报告和案例源代码须在本次小组讨论会前提交