织梦CMS - 轻松建站从此开始!

罗索

生产者-消费者

jackyhwei 发布于 2010-10-13 16:16 点击:次 
生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
TAG:

这个模式的详细解释请参考:http://blog.csdn.net/program_think/archive/2009/03/25/4022087.aspx

简要的说明一下这个模式:

消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。

生产者/消费者模式实现:

 

  1. #include <windows.h>  
  2. #include <iostream>  
  3.  
  4. const unsigned short SIZE_OF_BUFFER = 10; //缓冲区长度  
  5. unsigned short ProductID = 0; //产品号  
  6. unsigned short ConsumeID = 0; //将被消耗的产品号  
  7. unsigned short in = 0; //产品进缓冲区时的缓冲区下标  
  8. unsigned short out = 0; //产品出缓冲区时的缓冲区下标  
  9.  
  10. int g_buffer[SIZE_OF_BUFFER]; //缓冲区是个循环队列  
  11. bool g_continue = true//控制程序结束  
  12. HANDLE g_hMutex; //用于线程间的互斥  
  13. HANDLE g_hFullSemaphore; //当缓冲区满时迫使生产者等待  
  14. HANDLE g_hEmptySemaphore; //当缓冲区空时迫使消费者等待  
  15.  
  16. DWORD WINAPI Producer(LPVOID); //生产者线程  
  17. DWORD WINAPI Consumer(LPVOID); //消费者线程  
  18.  
  19. int main()  
  20. {  
  21. g_hMutex = CreateMutex(NULL,FALSE,NULL);  
  22. //函数功能:建立互斥体,用来同步。如果一个线程获取了互斥体,
  23. //则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。 
  24. //互斥体的好处是可以在进程间共享 
  25.  
  26. //函数原形: 
  27. //HANDLE CreateMutex(  
  28. // LPSECURITY_ATTRIBUTES lpMutexAttributes,  
  29. // BOOL bInitialOwner,  
  30. // LPCTSTR lpName  
  31. // );  
  32.   
  33. //参数说明: 
  34. //lpMutexAttributes: 
  35. //  指向一个SECURITY_ATTRIBUTES结构的指针,这个结构决定互斥体句柄是否被子进程继承。 
  36. //bInitialOwner: 
  37. //  布尔类型,决定互斥体的创建者是否为拥有者 
  38. //TRUE代表主线程拥有互斥对象,但是主线程没有释放该对象,互斥对象谁拥有,谁释放。 
  39. //FLASE代表当前没有线程拥有这个互斥对象 
  40. //lpName: 
  41. //  指向互斥体名字字符串的指针。互斥体可以有名字。 
  42.      
  43. g_hFullSemaphore = CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1,NULL); 
  44. //函数功能:创建信号量 
  45. //在开发软件的过程中,多线程的程序往往需要实现相互通讯,比如几个线程添加一个消息到队列里, 
  46. //而另一个线程在睡眠时,就需要唤醒那个线程来处理事情。在这其中,就需要使用到信号量来进行同步。 
  47. //CreateSemaphore是创建信号量,ReleaseSemaphore是增加信号量。 
  48.  
  49. //函数原形: 
  50. //HANDLE 
  51. // WINAPI 
  52. // CreateSemaphoreW( 
  53.     // __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, 
  54. // __in LONG lInitialCount, 
  55.     // __in LONG lMaximumCount, 
  56.     // __in_opt LPCWSTR lpName 
  57. // ); 
  58.  
  59. //参数说明: 
  60. //lpSemaphoreAttributes是信号量的安全属性。 
  61. //lInitialCount是初始化的信号量。 
  62. //lMaximumCount是允许信号量增加到最大值。 
  63. //lpName是信号量的名称。 
  64.  
  65.   
  66. g_hEmptySemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL);  
  67.  
  68.  
  69. const unsigned short PRODUCERS_COUNT = 3; //生产者的个数  
  70. const unsigned short CONSUMERS_COUNT = 1; //消费者的个数  
  71. const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT;
  72. //总的线程数(不是进程数)  
  73.  
  74. HANDLE hThreads[PRODUCERS_COUNT]; //各线程的handle  
  75. DWORD producerID[CONSUMERS_COUNT]; //生产者线程的标识符  
  76. DWORD consumerID[THREADS_COUNT]; //消费者线程的标识符  
  77.  
  78. //创建PRODUCERS_COUNT个线程 
  79. for (int i=0;i<PRODUCERS_COUNT;++i){  
  80. hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);  
  81.  
  82. //函数功能:创建线程 
  83. /*HANDLE 
  84. WINAPI 
  85. CreateThread( 
  86. __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, 
  87. __inSIZE_T dwStackSize, 
  88. __inLPTHREAD_START_ROUTINE lpStartAddress, 
  89. __in_opt LPVOID lpParameter, 
  90. __inDWORD dwCreationFlags, 
  91. __out_opt LPDWORD lpThreadId 
  92. ); 
  93.  
  94. lpThreadAttributes是线程的属性。 
  95. dwStackSize是线程的栈大小。 
  96. lpStartAddress是线程函数的开始地址。 
  97. lpParameter是传送给线程函数的参数。 
  98. dwCreationFlags是创建线程标志,比如挂起线程。 
  99. lpThreadId是标识这个线程的ID。*/ 
  100. //注意:lpThreadId是输出参数,也就是说这个线程的ID被保存在lpThreadId中。 
  101. //lpStartAddress是把这个线程和这个函数关联起来,
  102. //也就是这个线程一旦创建就执行这个函数。 
  103.  
  104.  
  105.  
  106. if (hThreads[i]==NULL) return -1;  
  107. }  
  108.   
  109. //创建CONSUMERS_COUNT个线程 
  110. for ( int i=0;i<CONSUMERS_COUNT;++i){  
  111. hThreads[PRODUCERS_COUNT+i]=
  112. CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]);  
  113. if (hThreads[i]==NULL) return -1;  
  114. }  
  115.  
  116. while(g_continue){  
  117. if(getchar()){ //按回车后终止程序运行 
  118. g_continue = false;  
  119. }  
  120. }  
  121.  
  122. return 0;  
  123. }  
  124.  
  125.  //生产一个产品,并输出提示信息 
  126. void Produce()  
  127. {  
  128. std::cerr << "Producing " << ++ProductID << " ... ";  
  129. std::cerr << "Succeed" << std::endl;  
  130. }  
  131.  
  132. //增加产品到缓冲区 
  133. void Append()  
  134. {  
  135. std::cerr << "Appending a product ... ";  
  136. g_buffer[in] = ProductID;  
  137. in = (in+1)%SIZE_OF_BUFFER; //这句很经典,构造循环队列的关键 
  138. std::cerr << "Succeed" << std::endl;  
  139.  
  140. //输出缓冲区当前的状态  
  141. for (int i=0;i<SIZE_OF_BUFFER;++i){  
  142. std::cout << i <<": " << g_buffer[i];  
  143. if (i==in) std::cout << " <-- 生产";  
  144. if (i==out) std::cout << " <-- 消费";  
  145. std::cout << std::endl;  
  146. }  
  147. }  
  148.  
  149.  //从缓冲区移除产品 
  150. void Take()  
  151. {  
  152. std::cerr << "Taking a product ... ";  
  153. ConsumeID = g_buffer[out];  
  154. out = (out+1)%SIZE_OF_BUFFER;  
  155. std::cerr << "Succeed" << std::endl;  
  156.  
  157. //输出缓冲区当前的状态  
  158. for (int i=0;i<SIZE_OF_BUFFER;++i){  
  159. std::cout << i <<": " << g_buffer[i];  
  160. if (i==in) std::cout << " <-- 生产";  
  161. if (i==out) std::cout << " <-- 消费";  
  162. std::cout << std::endl;  
  163. }  
  164. }  
  165.  
  166. //消费一个产品 
  167. void Consume()  
  168. {  
  169. std::cerr << "Consuming " << ConsumeID << " ... ";  
  170. std::cerr << "Succeed" << std::endl;  
  171. }  
  172.  
  173. //生产者 
  174. DWORD WINAPI Producer(LPVOID lpPara)  
  175. {  
  176. while(g_continue){  
  177. WaitForSingleObject(g_hFullSemaphore,INFINITE);  
  178. //用来检测hHandle事件的信号状态 
  179. /*WINBASEAPI 
  180. DWORD 
  181. WINAPI 
  182. WaitForSingleObject( 
  183. __in HANDLE hHandle, 
  184. __in DWORD dwMilliseconds 
  185. ); 
  186. hHandle是等待对象的句柄。 
  187. dwMilliseconds是等待的时间条件,INFINITE表示永远等待下去。*/ 
  188.  
  189. WaitForSingleObject(g_hMutex,INFINITE);  
  190. Produce();  
  191. Append();  
  192. Sleep(1500);  
  193.      
  194. ReleaseMutex(g_hMutex);  
  195. //Releases ownership of the specified mutex object. 
  196. //Parameters: A handle to the mutex object 
  197.  
  198.  
  199. ReleaseSemaphore(g_hEmptySemaphore,1,NULL); 
  200. /*WINAPI 
  201. ReleaseSemaphore( 
  202. __inHANDLE hSemaphore, 
  203. __inLONG lReleaseCount, 
  204. __out_opt LPLONG lpPreviousCount 
  205. ); 
  206.  
  207. hSemaphore是要增加的信号量句柄。 
  208. lReleaseCount是增加的计数。 
  209. lpPreviousCount是增加前的数值返回。*/ 
  210.  
  211.   
  212. }  
  213. return 0;  
  214. }  
  215.  
  216. //消费者 
  217. DWORD WINAPI Consumer(LPVOID lpPara)  
  218. {  
  219. while(g_continue){  
  220. WaitForSingleObject(g_hEmptySemaphore,INFINITE);  
  221. WaitForSingleObject(g_hMutex,INFINITE);  
  222. Take();  
  223. Consume();  
  224. Sleep(1500);  
  225. ReleaseMutex(g_hMutex);  
  226. ReleaseSemaphore(g_hFullSemaphore,1,NULL);  
  227. }  
  228. return 0;  
(yfqvip)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201010/10300.html]
本文出处:CSDN博客 作者:yfqvip
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容