日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

秒杀多线程第十篇 生产者消费者问题

發布時間:2024/4/11 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 秒杀多线程第十篇 生产者消费者问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

經典線程同步問題之后,我們來看看生產者消費者問題及讀者寫者問題。生產者消費者問題是一個著名的線程同步問題,該問題描述如下:有一個生產者在生產產品,這些產品將提供給若干個消費者去消費,為了使生產者和消費者能并發執行,在兩者之間設置一個具有多個緩沖區的緩沖池,生產者將它生產的產品放入一個緩沖區中,消費者可以從緩沖區中取走產品進行消費,顯然生產者和消費者之間必須保持同步,即不允許消費者到一個空的緩沖區中取產品,也不允許生產者向一個已經放入產品的緩沖區中再次投放產品。

??? 這個生產者消費者題目不僅常用于操作系統的課程設計,也常常在程序員和軟件設計師考試中出現。并且在計算機考研的專業課考試中也是一個非常熱門的問題。因此現在就針對這個問題進行詳細深入的解答。

?

??? 首先來簡化問題,先假設生產者和消費者都只有一個,且緩沖區也只有一個。這樣情況就簡便多了。

??? 第一.從緩沖區取出產品和向緩沖區投放產品必須是互斥進行的。可以用關鍵段和互斥量來完成。

??? 第二.生產者要等待緩沖區為空,這樣才可以投放產品,消費者要等待緩沖區不為空,這樣才可以取出產品進行消費。并且由于有二個等待過程,所以要用二個事件或信號量來控制。

??? 考慮這二點后,代碼很容易寫出來。另外為了美觀起見,將消費者的輸出顏色設置為彩色,有關如何在控制臺下設置彩色輸出請參閱《VC?控制臺顏色設置》。

[cpp]?view plaincopy
  • //1生產者?1消費者?1緩沖區??
  • //使用二個事件,一個表示緩沖區空,一個表示緩沖區滿。??
  • //再使用一個關鍵段來控制緩沖區的訪問??
  • #include?<stdio.h>??
  • #include?<process.h>??
  • #include?<windows.h>??
  • //設置控制臺輸出顏色??
  • BOOL?SetConsoleColor(WORD?wAttributes)??
  • {??
  • ????HANDLE?hConsole?=?GetStdHandle(STD_OUTPUT_HANDLE);??
  • ????if?(hConsole?==?INVALID_HANDLE_VALUE)??
  • ????????return?FALSE;?????
  • ????return?SetConsoleTextAttribute(hConsole,?wAttributes);??
  • }??
  • const?int?END_PRODUCE_NUMBER?=?10;???//生產產品個數??
  • int?g_Buffer;????????????????????????//緩沖區??
  • //事件與關鍵段??
  • CRITICAL_SECTION?g_cs;??
  • HANDLE?g_hEventBufferEmpty,?g_hEventBufferFull;??
  • //生產者線程函數??
  • unsigned?int?__stdcall?ProducerThreadFun(PVOID?pM)??
  • {??
  • ????for?(int?i?=?1;?i?<=?END_PRODUCE_NUMBER;?i++)??
  • ????{??
  • ????????//等待緩沖區為空??
  • ????????WaitForSingleObject(g_hEventBufferEmpty,?INFINITE);??
  • ??
  • ????????//互斥的訪問緩沖區??
  • ????????EnterCriticalSection(&g_cs);??
  • ????????g_Buffer?=?i;??
  • ????????printf("生產者將數據%d放入緩沖區\n",?i);??
  • ????????LeaveCriticalSection(&g_cs);??
  • ??????????
  • ????????//通知緩沖區有新數據了??
  • ????????SetEvent(g_hEventBufferFull);??
  • ????}??
  • ????return?0;??
  • }??
  • //消費者線程函數??
  • unsigned?int?__stdcall?ConsumerThreadFun(PVOID?pM)??
  • {??
  • ????volatile?bool?flag?=?true;??
  • ????while?(flag)??
  • ????{??
  • ????????//等待緩沖區中有數據??
  • ????????WaitForSingleObject(g_hEventBufferFull,?INFINITE);??
  • ??????????
  • ????????//互斥的訪問緩沖區??
  • ????????EnterCriticalSection(&g_cs);??
  • ????????SetConsoleColor(FOREGROUND_GREEN);??
  • ????????printf("??消費者從緩沖區中取數據%d\n",?g_Buffer);??
  • ????????SetConsoleColor(FOREGROUND_RED?|?FOREGROUND_GREEN?|?FOREGROUND_BLUE);??
  • ????????if?(g_Buffer?==?END_PRODUCE_NUMBER)??
  • ????????????flag?=?false;??
  • ????????LeaveCriticalSection(&g_cs);??
  • ??????????
  • ????????//通知緩沖區已為空??
  • ????????SetEvent(g_hEventBufferEmpty);??
  • ??
  • ????????Sleep(10);?//some?other?work?should?to?do??
  • ????}??
  • ????return?0;??
  • }??
  • int?main()??
  • {??
  • ????printf("??生產者消費者問題???1生產者?1消費者?1緩沖區\n");??
  • ????printf("?--?by?MoreWindows(?http://blog.csdn.net/MoreWindows?)?--\n\n");??
  • ??
  • ????InitializeCriticalSection(&g_cs);??
  • ????//創建二個自動復位事件,一個表示緩沖區是否為空,另一個表示緩沖區是否已經處理??
  • ????g_hEventBufferEmpty?=?CreateEvent(NULL,?FALSE,?TRUE,?NULL);??
  • ????g_hEventBufferFull?=?CreateEvent(NULL,?FALSE,?FALSE,?NULL);??
  • ??????
  • ????const?int?THREADNUM?=?2;??
  • ????HANDLE?hThread[THREADNUM];??
  • ??????
  • ????hThread[0]?=?(HANDLE)_beginthreadex(NULL,?0,?ProducerThreadFun,?NULL,?0,?NULL);??
  • ????hThread[1]?=?(HANDLE)_beginthreadex(NULL,?0,?ConsumerThreadFun,?NULL,?0,?NULL);??
  • ????WaitForMultipleObjects(THREADNUM,?hThread,?TRUE,?INFINITE);??
  • ????CloseHandle(hThread[0]);??
  • ????CloseHandle(hThread[1]);??
  • ??????
  • ????//銷毀事件和關鍵段??
  • ????CloseHandle(g_hEventBufferEmpty);??
  • ????CloseHandle(g_hEventBufferFull);??
  • ????DeleteCriticalSection(&g_cs);??
  • ????return?0;??
  • }??
  • 運行結果如下所示:

    可以看出生產者與消費者已經是有序的工作了。

    ?

    ??? 然后再對這個簡單生產者消費者問題加大難度。將消費者改成2個,緩沖池改成擁有4個緩沖區的大緩沖池。

    ????如何來思考了這個問題了?首先根據上面分析的二點,可以知道生產者和消費者由一個變成多個的影響不大,唯一要注意的是緩沖池變大了,回顧一下《秒殺多線程第八篇?經典線程同步 信號量Semaphore》中的信號量,不難得出用二個信號量就可以解決這種緩沖池有多個緩沖區的情況——用一個信號量A來記錄為空的緩沖區個數,另一個信號量B記錄非空的緩沖區個數,然后生產者等待信號量A,消費者等待信號量B就可以了。因此可以仿照上面的代碼來實現復雜生產者消費者問題,示例代碼如下:

    [cpp]?view plaincopy
  • //1生產者?2消費者?4緩沖區??
  • #include?<stdio.h>??
  • #include?<process.h>??
  • #include?<windows.h>??
  • //設置控制臺輸出顏色??
  • BOOL?SetConsoleColor(WORD?wAttributes)??
  • {??
  • ????HANDLE?hConsole?=?GetStdHandle(STD_OUTPUT_HANDLE);??
  • ????if?(hConsole?==?INVALID_HANDLE_VALUE)??
  • ????????return?FALSE;??
  • ??????
  • ????return?SetConsoleTextAttribute(hConsole,?wAttributes);??
  • }??
  • const?int?END_PRODUCE_NUMBER?=?8;??//生產產品個數??
  • const?int?BUFFER_SIZE?=?4;??????????//緩沖區個數??
  • int?g_Buffer[BUFFER_SIZE];??????????//緩沖池??
  • int?g_i,?g_j;??
  • //信號量與關鍵段??
  • CRITICAL_SECTION?g_cs;??
  • HANDLE?g_hSemaphoreBufferEmpty,?g_hSemaphoreBufferFull;??
  • //生產者線程函數??
  • unsigned?int?__stdcall?ProducerThreadFun(PVOID?pM)??
  • {??
  • ????for?(int?i?=?1;?i?<=?END_PRODUCE_NUMBER;?i++)??
  • ????{??
  • ????????//等待有空的緩沖區出現??
  • ????????WaitForSingleObject(g_hSemaphoreBufferEmpty,?INFINITE);??
  • ??
  • ????????//互斥的訪問緩沖區??
  • ????????EnterCriticalSection(&g_cs);??
  • ????????g_Buffer[g_i]?=?i;??
  • ????????printf("生產者在緩沖池第%d個緩沖區中投放數據%d\n",?g_i,?g_Buffer[g_i]);??
  • ????????g_i?=?(g_i?+?1)?%?BUFFER_SIZE;??
  • ????????LeaveCriticalSection(&g_cs);??
  • ??
  • ????????//通知消費者有新數據了??
  • ????????ReleaseSemaphore(g_hSemaphoreBufferFull,?1,?NULL);??
  • ????}??
  • ????printf("生產者完成任務,線程結束運行\n");??
  • ????return?0;??
  • }??
  • //消費者線程函數??
  • unsigned?int?__stdcall?ConsumerThreadFun(PVOID?pM)??
  • {??
  • ????while?(true)??
  • ????{??
  • ????????//等待非空的緩沖區出現??
  • ????????WaitForSingleObject(g_hSemaphoreBufferFull,?INFINITE);??
  • ??????????
  • ????????//互斥的訪問緩沖區??
  • ????????EnterCriticalSection(&g_cs);??
  • ????????SetConsoleColor(FOREGROUND_GREEN);??
  • ????????printf("??編號為%d的消費者從緩沖池中第%d個緩沖區取出數據%d\n",?GetCurrentThreadId(),?g_j,?g_Buffer[g_j]);??
  • ????????SetConsoleColor(FOREGROUND_RED?|?FOREGROUND_GREEN?|?FOREGROUND_BLUE);??
  • ????????if?(g_Buffer[g_j]?==?END_PRODUCE_NUMBER)//結束標志??
  • ????????{??
  • ????????????LeaveCriticalSection(&g_cs);??
  • ????????????//通知其它消費者有新數據了(結束標志)??
  • ????????????ReleaseSemaphore(g_hSemaphoreBufferFull,?1,?NULL);??
  • ????????????break;??
  • ????????}??
  • ????????g_j?=?(g_j?+?1)?%?BUFFER_SIZE;??
  • ????????LeaveCriticalSection(&g_cs);??
  • ??
  • ????????Sleep(50);?//some?other?work?to?do??
  • ??
  • ????????ReleaseSemaphore(g_hSemaphoreBufferEmpty,?1,?NULL);??
  • ????}??
  • ????SetConsoleColor(FOREGROUND_GREEN);??
  • ????printf("??編號為%d的消費者收到通知,線程結束運行\n",?GetCurrentThreadId());??
  • ????SetConsoleColor(FOREGROUND_RED?|?FOREGROUND_GREEN?|?FOREGROUND_BLUE);??
  • ????return?0;??
  • }??
  • int?main()??
  • {??
  • ????printf("??生產者消費者問題???1生產者?2消費者?4緩沖區\n");??
  • ????printf("?--?by?MoreWindows(?http://blog.csdn.net/MoreWindows?)?--\n\n");??
  • ??
  • ????InitializeCriticalSection(&g_cs);??
  • ????//初始化信號量,一個記錄有產品的緩沖區個數,另一個記錄空緩沖區個數.??
  • ????g_hSemaphoreBufferEmpty?=?CreateSemaphore(NULL,?4,?4,?NULL);??
  • ????g_hSemaphoreBufferFull??=?CreateSemaphore(NULL,?0,?4,?NULL);??
  • ????g_i?=?0;??
  • ????g_j?=?0;??
  • ????memset(g_Buffer,?0,?sizeof(g_Buffer));??
  • ??
  • ????const?int?THREADNUM?=?3;??
  • ????HANDLE?hThread[THREADNUM];??
  • ????//生產者線程??
  • ????hThread[0]?=?(HANDLE)_beginthreadex(NULL,?0,?ProducerThreadFun,?NULL,?0,?NULL);??
  • ????//消費者線程??
  • ????hThread[1]?=?(HANDLE)_beginthreadex(NULL,?0,?ConsumerThreadFun,?NULL,?0,?NULL);??
  • ????hThread[2]?=?(HANDLE)_beginthreadex(NULL,?0,?ConsumerThreadFun,?NULL,?0,?NULL);??
  • ????WaitForMultipleObjects(THREADNUM,?hThread,?TRUE,?INFINITE);??
  • ????for?(int?i?=?0;?i?<?THREADNUM;?i++)??
  • ????????CloseHandle(hThread[i]);??
  • ??
  • ????//銷毀信號量和關鍵段??
  • ????CloseHandle(g_hSemaphoreBufferEmpty);??
  • ????CloseHandle(g_hSemaphoreBufferFull);??
  • ????DeleteCriticalSection(&g_cs);??
  • ????return?0;??
  • }??
  • 運行結果如下圖所示:

    輸出結果證明各線程的同步和互斥已經完成了。

    ?

    至此,生產者消費者問題已經圓滿的解決了,下面作個總結:

    1.首先要考慮生產者與消費者對緩沖區操作時的互斥。

    2.不管生產者與消費者有多少個,緩沖池有多少個緩沖區。都只有二個同步過程——分別是生產者要等待有空緩沖區才能投放產品,消費者要等待有非空緩沖區才能去取產品。

    ?

    下一篇《秒殺多線程第十一篇讀者寫者問題》將介紹另一個著名的同步問題——讀者寫者問題,歡迎大家再來參閱。

    ?

    轉載請標明出處,原文地址:http://blog.csdn.net/morewindows/article/details/7577591

    如果覺得本文對您有幫助,請點擊‘頂’支持一下,您的支持是我寫作最大的動力,謝謝。

    ?

    總結

    以上是生活随笔為你收集整理的秒杀多线程第十篇 生产者消费者问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。