生產者和消費者:C++

來源:互聯網
上載者:User

#include<windows.h>
#include<fstream.h>
#include<stdio.h>
#include<string>
#include<conio.h>

//定義一些常量;

//本程式允許的最大臨界區數;
#define MAX_BUFFER_NUM    10

//秒到微秒的乘法因子;
#define INTE_PER_SEC 1000

//本程式允許的生產和消費線程的總數;
#define MAX_THREAD_NUM 64

//定義一個結構,記錄在測試檔案中指定的每一個線程的參數
struct ThreadInfo
{
    int    serial;                                //線程式列號
    char    entity;                            //是P還是C
    double    delay;                            //線程延遲
    int    thread_request[MAX_THREAD_NUM];     //線程請求隊列
    int    n_request;                            //請求個數
};

//全域變數的定義

//臨界區對象的聲明,用於管理緩衝區的互斥訪問;
int            Buffer_Critical[MAX_BUFFER_NUM]; //緩衝區聲明,用於存放產品;
ThreadInfo    Thread_Info[MAX_THREAD_NUM];    //線程資訊數組;
HANDLE        h_Thread[MAX_THREAD_NUM];        //用於儲存每個線程控制代碼的數組;

HANDLE    empty_semaphore;                    //一個訊號量;
HANDLE    h_mutex;                            //一個互斥量;
HANDLE    h_Semaphore[MAX_THREAD_NUM];        //生產者允許消費者開始消費的訊號量;
CRITICAL_SECTION    PC_Critical[MAX_BUFFER_NUM];   

DWORD        n_Thread = 0;                    //實際的線程的數目;
DWORD        n_Buffer_or_Critical;            //實際的緩衝區或者臨界區的數目;

//生產消費及輔助函數的聲明
void Produce(void *p);
void Consume(void *p);   
bool IfInOtherRequest(int);
int    FindProducePositon();
int    FindBufferPosition(int);

int main(int argc, char **argv)
{
    //聲明所需變數;
    DWORD        wait_for_all;
    ifstream    inFile;
   
    if (argc!=2)    {
        printf("Usage:%s <File>/n",argv[0]);
        return 1;
    }

    //初始化緩衝區;
    for(int i=0;i< MAX_BUFFER_NUM;i++)
        Buffer_Critical[i] = -1;       
   
    //初始化每個線程的請求隊列;
    for(int j=0;j<MAX_THREAD_NUM;j++) {
        for(int k=0;k<MAX_THREAD_NUM;k++)
            Thread_Info[j].thread_request[k] = -1;

        Thread_Info[j].n_request = 0;
    }
   
    //初始化臨界區;
    for(i =0;i< MAX_BUFFER_NUM;i++)
        InitializeCriticalSection(&PC_Critical[i]);

    //開啟輸入檔案,按照規定的格式提取線程等資訊;
    inFile.open(argv[1]);

    //從檔案中獲得實際的緩衝區的數目,即測試檔案第一行的資訊;
    inFile >> n_Buffer_or_Critical;
    inFile.get(); // 讀取測試檔案中的空格,將檔案指標指向下一行;
    printf("輸入檔案是:/n");

    //回顯獲得的緩衝區的數目資訊;
    printf("%d /n",(int) n_Buffer_or_Critical);

    //提取每個線程的資訊到相應資料結構中;
    while(inFile){
        inFile >> Thread_Info[n_Thread].serial;
        inFile >> Thread_Info[n_Thread].entity;
        inFile >> Thread_Info[n_Thread].delay;

        char c;
        inFile.get(c);

        while(c!='/n'&& !inFile.eof()) {
        inFile>> Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_request++];
        inFile.get(c);   
        }
       
        n_Thread++;
    }

    //回顯獲得的線程資訊,便於確認正確性;   
    for(j=0;j<(int) n_Thread;j++) {
        int    Temp_serial = Thread_Info[j].serial;
        char   Temp_entity = Thread_Info[j].entity;
        double Temp_delay   = Thread_Info[j].delay;
       
        printf(" /nthread%2d    %c    %f   ",Temp_serial,Temp_entity,Temp_delay);

        int Temp_request = Thread_Info[j].n_request;

        for(int k=0;k<Temp_request;k++)
            printf(" %d    ", Thread_Info[j].thread_request[k]);

        cout<<endl;
    }
   
    printf("/n/n");

     //建立在類比過程中幾個必要的訊號量
    empty_semaphore = CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical,
                                "semaphore_for_empty");
    h_mutex    = CreateMutex(NULL,FALSE,"mutex_for_update");

    //下面這個迴圈用線程的ID號來為相應生產線程的產品讀寫時所
    //使用的同步訊號量命名;
    for(j=0;j<(int)n_Thread;j++) {            
        char lp[]="semaphore_for_produce_";
        int temp =j;
        while(temp){
        char c = (char)(temp%10);
        strcat(lp,&c);
        temp/=10;
        }

        h_Semaphore[j+1]=CreateSemaphore(NULL,0,n_Thread,lp);
    }

    //建立生產者和消費者線程;
    for(i =0;i< (int) n_Thread;i++) {
        if(Thread_Info[i].entity =='P')
            h_Thread[i]= CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce),
                                    &(Thread_Info[i]),0,NULL);
        else
           h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume),
                                &(Thread_Info[i]),0,NULL);
    }

    //主程式等待各個線程的動作結束;
    wait_for_all = WaitForMultipleObjects(n_Thread,h_Thread,TRUE,-1);

    printf(" /n /nALL Producer and consumer have finished their work. /n");
    printf("Press any key to quit!/n");
    _getch();
    return 0;
}

//確認是否還有對同一產品的消費請求未執行;
bool IfInOtherRequest(int req)
{
    for(int i=0;i<n_Thread;i++)
        for(int j=0;j<Thread_Info[i].n_request;j++)
            if(Thread_Info[i].thread_request[j] == req)
                return TRUE;

    return FALSE;
}

//找出當前可以進行產品生產的空緩衝區位置;
int    FindProducePosition()
{
    int EmptyPosition;
    for (int i =0;i<n_Buffer_or_Critical;i++)
        if(Buffer_Critical[i] == -1) {
            EmptyPosition = i;

            //用下面這個特殊值表示本緩衝區正處於被寫狀態;
            Buffer_Critical[i] = -2;
            break;
        }
    return EmptyPosition;
}

//找出當前所需生產者生產的產品的位置;
int FindBufferPosition(int ProPos)
{
    int TempPos;
    for (int i =0 ;i<n_Buffer_or_Critical;i++)
        if(Buffer_Critical[i]==ProPos){
            TempPos = i;
            break;
        }
    return TempPos;
}

//生產者進程
void Produce(void *p)
{
    //局部變數聲明;
    DWORD    wait_for_semaphore,wait_for_mutex,m_delay;
    int        m_serial;

    //獲得本線程的資訊;
    m_serial = ((ThreadInfo*)(p))->serial;
    m_delay = (DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC);

    Sleep(m_delay);
    //開始請求生產
    printf("Producer %2d sends the produce require./n",m_serial);

    //互斥訪問下一個可用於生產的空臨界區,實現寫寫互斥;
    wait_for_mutex = WaitForSingleObject(h_mutex,-1);

    //確認有空緩衝區可供生產,同時將空位置數empty減1;用於生產者和消費者的同步;
   //若沒有則一直等待,直到消費者進程釋放資源為止;
    wait_for_semaphore    = WaitForSingleObject(empty_semaphore,-1);
                       

    int ProducePos = FindProducePosition();
    ReleaseMutex(h_mutex);

    //生產者在獲得自己的空位置並做上標記後,以下的寫操作在生產者之間可以並發;
    //核心生產步驟中,程式將生產者的ID作為產品編號放入,方便消費者識別;
    printf("Producer %2d begin to produce at position %2d./n",m_serial,ProducePos);
    Buffer_Critical[ProducePos] = m_serial;
    printf("Producer %2d finish producing :/n ",m_serial);
    printf("    position[ %2d ]:%3d /n/n" ,ProducePos,Buffer_Critical[ProducePos]);

    //使生產者寫的緩衝區可以被多個消費者使用,實現讀寫同步;
    ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL);
}

//消費者進程
void Consume(void * p)
{
    //局部變數聲明;
    DWORD    wait_for_semaphore,m_delay;
    int    m_serial,m_requestNum;                //消費者的序號和請求的數目;
    int    m_thread_request[MAX_THREAD_NUM];    //本消費線程的請求隊列;
   
    //提取本線程的資訊到本地;
    m_serial = ((ThreadInfo*)(p))->serial;
    m_delay = (DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC);
    m_requestNum = ((ThreadInfo *)(p))->n_request;
   
    for (int i = 0;i<m_requestNum;i++)
        m_thread_request[i] = ((ThreadInfo*)(p))->thread_request[i];

    Sleep(m_delay);   

    //迴圈進行所需產品的消費
    for(i =0;i<m_requestNum;i++){  
       
    //請求消費下一個產品
    printf("Consumer %2d request to consume %2d product/n",m_serial,m_thread_request[i]);

    //如果對應生產者沒有生產,則等待;如果生產了,允許的消費者數目-1;實現了讀寫同步;
    wait_for_semaphore=WaitForSingleObject(h_Semaphore[m_thread_request[i]],-1);

    //查詢所需產品放到緩衝區的號       
    int BufferPos=FindBufferPosition(m_thread_request[i]);   
           
    //開始進行具體緩衝區的消費處理,讀和讀在該緩衝區上仍然是互斥的;
    //進入臨界區後執行消費動作;並在完成此次請求後,通知另外的消費者本處請求已
    //經滿足;同時如果對應的產品使用完畢,就做相應處理;並給出相應動作的介面提
    //示;該相應處理指將相應緩衝區清空,並增加代表空緩衝區的訊號量;
    EnterCriticalSection(&PC_Critical[BufferPos]);
    printf("Consumer %2d begin to consume %2d product /n",m_serial,m_thread_request[i]);
         ((ThreadInfo*)(p))->thread_request[i] =-1;

    if(!IfInOtherRequest(m_thread_request[i])) {
        Buffer_Critical[BufferPos] = -1;        //-1標記緩衝區為空白;
        printf("Consumer %2d finish consuming %2d:/n ",m_serial,m_thread_request[i]);
        printf("    position[ %2d ]:%3d /n/n" ,BufferPos,Buffer_Critical[BufferPos]);
        ReleaseSemaphore(empty_semaphore,1,NULL);
    }       
    else {
        printf("Consumer %2d finish consuming product %2d/n/n ",m_serial,m_thread_request[i]);
    }

    //離開臨界區
    LeaveCriticalSection(&PC_Critical[BufferPos]);
    }
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.