亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

生產者-消費者問題詳解

發布時間:2020-06-30 11:43:28 來源:網絡 閱讀:2438 作者:Adam的blog 欄目:開發技術

1. 前言

??生產者-消費者問題是經典的線程同步問題(我會用java和c分別實現),主要牽扯到三個點:
?一:能否互斥訪問共享資源(不能同時訪問共享數據);
?二:當公共容器滿時,生產者能否繼續生產(生產者應阻塞并喚醒消費者消費);
?三:當公共容器為空時,消費者能否繼續消費(消費者應阻塞并喚醒生產者生產)。

2. JAVA實現

?step0:在java中我們創建線程是通過繼承Thread類或者繼承Runnable接口并實現他的run方法來實現的,這里我們采用后者
?step1:定義一個放饅頭的大筐(一個公共的容器類),這個筐具有push方法和pop方法,分別對應往筐中放饅頭和從筐中取出饅頭。由于在同一個時間段內只能有一個線程訪問此方法,so,我們給這兩個方法加鎖。代碼如下:

class SyncStack{//定義放饅頭的筐,是棧,先進后出
    int index = 0;//定義筐里面饅頭的編號
    WoTou[] arrWT = new WoTou[6];//定義一個引用類型的數組

    public synchronized void push(WoTou wt){//定義往筐里放饅頭的方法,由于需要保證在一段特定時間里只能有一個線程訪問此方法,所以用synchronized關鍵字
        while(index == arrWT.length){
            try{
                this.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notify();
        arrWT[index] = wt;
        index ++;
    }

    public synchronized WoTou pop(){//定義從筐里往外拿饅頭的方法,同理在一段時間只能有一個線程訪問此方法,所以用synchronized關鍵字
        while(index == 0){
            try{
                this.wait();//當前的正在我這個對象訪問的這個線程wait
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notify();//喚醒一個等待的線程,叫醒一個正在wait在我這個對象上的線程
        index --;
        return arrWT[index];
    }
}

?step2:分別定義生產者和消費者的類,他們均是不同的線程。給出代碼:

class Producer implements Runnable{//定義生產者這個類,是一個線程
    SyncStack ss = null;//聲明了筐子的引用變量ss,表示做饅頭的人往那個筐里放饅頭
    Producer(SyncStack ss){
        this.ss = ss;
    }

    public void run(){
        for(int i=0; i<20; i++){
            WoTou wt = new WoTou(i);//new出一個饅頭,該饅頭的編號為i
            ss.push(wt);//把第i個饅頭放到筐中
            System.out.println(i);
            System.out.println("生產了:" + wt);    
            try{
                Thread.sleep((int)(Math.random() * 200));//每生產一個睡眠1s
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable{//定義消費者這個類,也是一個線程
    SyncStack ss = null;//聲明了筐子的引用變量ss,表示吃饅頭的人往那個筐里拿饅頭
    Consumer(SyncStack ss){
        this.ss = ss;
    }

    public void run(){
        for(int i=0; i<20; i++){
            WoTou wt = ss.pop();//取出一個饅頭
            System.out.println("消費了:" + wt);//開始吃饅頭

            try{
                Thread.sleep((int)(Math.random() * 1000));
                //每消費一個睡眠1s
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

?step3:我們事先定義了一個饅頭類,現在給出測試類測試:

/*
wait和sleep的區別
    -1:sleep不需要喚醒,線程不會釋放對象鎖,屬于Thread類
    -2:wait需要notify()方法喚醒,線程會放棄對象鎖,屬于Object類
*/
public class ProducerConsumer{
    public static void main(String[] args){
        SyncStack ss = new SyncStack();
        Producer p = new Producer(ss);
        Consumer c = new Consumer(ss);

        new Thread(p).start();
        new Thread(c).start();
    }
}

class WoTou{//定義饅頭這個類
    int id;//定義饅頭的編號
    WoTou(int id){
        this.id = id;
    }
    public String toString(){//重寫toString方法
        return "WoTou:" + id;
    }
}

?step4:看下測試結果,發現符合我們事先說的那三點:
生產者-消費者問題詳解

3. C實現

?step0:c語言在Windows下實現線程的需要導入#include<process.h>頭文件,用_beginthread();來開始一個線程,用_endthread();來結束一個線程。具體操作方法,自行百度。
?step1:C語言中緩沖區對應公共容器,我們通過定義互斥信號量mutex來實現線程對緩沖池的互斥訪問。直接看下代碼操作:

#include<stdio.h>
#include<process.h>
#define N 10

//代表執行生產和消費的變量 
int in=0, out=0;

//線程結束的標志 
int flg_pro=0, flg_con=0;

//mutex:互斥信號量,實現線程對緩沖池的互斥訪問;
//empty和full:資源信號量,分別表示緩沖池中空緩沖池和滿緩沖池的數量(注意初值,從生產者的角度) 
int mutex=1, empty=N, full=0;

//打印測試 
void print(char c){
    printf("%c    一共生產了%d個窩頭,消費了%d個窩頭,現在有%d個窩頭\n", c, in, out, full);
}

//請求某個資源 
void wait(int *x){
    while((*x)<=0);
    (*x)--;
}

//釋放某個資源 
void signal(int *x){
    (*x)++;
} 

//生產者 
void produce(void *a){
    while(1){
//      printf("開始阻塞生產者\n"); 
        wait(&empty);   //申請一個緩沖區,看有無其他線程訪問 
        wait(&mutex);
//      printf("結束阻塞生產者\n");

        in++;

        signal(&mutex);  
        signal(&full);  //full加一,喚醒消費者,告訴消費者可以消費 

//      printf("結束生產。。。\n");
        print('p');

        Sleep(200);
        if(flg_pro == 1){
            _endthread();
        }   
    } 
} 

//消費者
void consumer(void * a){
    while(1){
//      printf("開始阻塞消費者\n");
        wait(&full);
        wait(&mutex);
//      printf("結束阻塞消費者\n");

        out++;

        signal(&mutex);
        signal(&empty);
//      printf("結束消費。。。\n");
        print('c');

        Sleep(200);
        if(flg_con == 1){
            _endthread();   
        }
    }
} 

//主函數 
int main(){
    _beginthread(consumer,0,NULL);  
    _beginthread(produce,0,NULL);
    //總的執行時間為1分鐘 
    Sleep(10000);
    flg_pro=flg_con=1;
    system("pause");
    return 0;
}

?step2:注意事項:
??1)用來實現互斥的wait(&mutex);signal(&mutex);必須成對出現在每一個線程中,對于資源信號量的waitsignal操作,分別成對出現在不同的線程中
??2)先執行對資源信號量的wait操作,在執行對互斥信號量的wait操作,不能顛倒否則導致死鎖。
?step3:測試結果,符合預期:
生產者-消費者問題詳解

4. 總結

?現在缺乏的是一種把生活中具體的問題抽象成代碼的能力,可能也是對c語言的不熟悉導致的問題,看著我宿舍大神寫的代碼,真漂亮,由衷的羨慕。熟知并非真知,還得多加思考才是。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

江都市| 婺源县| 松桃| 远安县| 莎车县| 克山县| 都昌县| 五河县| 饶阳县| 股票| 新邵县| 徐州市| 伊宁市| 民权县| 高雄县| 霞浦县| 田阳县| 噶尔县| 城步| 无极县| 太仓市| 宁阳县| 施甸县| 宁南县| 府谷县| 卓尼县| 吐鲁番市| 南涧| 永吉县| 外汇| 西林县| 资源县| 和龙市| 宁城县| 高邑县| 遵义县| 青岛市| 绥滨县| 炉霍县| 晋中市| 佛坪县|