生產者消費者模型(條件變量)

三種關系:互斥,同步,互斥和同步
兩類角色:生產者,消費者(線程)
一個交易場所:生產者消費者共享的區域

賣蘋果的模型

  • dish上面只有一個蘋果
  • 買家必須要等賣家把蘋果放到dish上才可以去買蘋果。
  • 賣家必須等待買家把蘋果買走才可以生產蘋果
  • pthread_mutex_lock(&mutex); 和pthread_mutex_unlock(&mutex); 成對出現,里面的操作為一個原子操作
  • pthread_cond_wait(&empty,&mutex);內部有一個加鎖解鎖操作
  • 過程詳解
    • 蘋果為0
    • 初始化時蘋果為0,買家在pthread_cond_wait(&empty,&mutex); 開始等待,賣家不進入while循環,生產蘋果后發出pthread_cond_signal(&empty);讓正在因dish上蘋果為0的買家停止等待pthread_cond_wait(&empty,&mutex);
    • 蘋果為1
    • 當一個賣家進入pthread_mutex_lock(&mutex); 但是發現蘋果為1時,就在while循環處等待pthread_cond_wait(&empty,&mutex);,直到買家發出信號 pthread_cond_signal(&full);賣家停止等待,此時蘋果為0,跳出while循環,開始生產蘋果。生產蘋果后發出pthread_cond_signal(&empty);讓正在因dish上蘋果為0的買家停止等待pthread_cond_wait(&empty,&mutex); 這樣這個過程就結束了
      *
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>int dish = 0;
pthread_cond_t full;
pthread_cond_t empty;
pthread_mutex_t mutex;void * consumer(void * arg)
{int id = (int)arg;while(1){pthread_mutex_lock(&mutex);//上鎖while(dish == 0){//買家發現沒有蘋果開始等待pthread_cond_wait(&empty,&mutex);}usleep(100000);dish = 0;printf("consumer %d get an apple!!\n", id);//給賣家發送信號pthread_cond_signal(&full);pthread_mutex_unlock(&mutex);//解鎖}return NULL;
}void * product(void *arg)
{int id = (int)arg;while(1){pthread_mutex_lock(&mutex);    while(dish == 1){pthread_cond_wait(&full,&mutex);}dish =1;printf("producer %d put an apple!!\n", id);      pthread_cond_signal(&empty);pthread_mutex_unlock(&mutex);}return NULL;
}int main()
{pthread_t tid;int set ;//初始化pthread_cond_init(&full,NULL);pthread_cond_init(&empty,NULL);pthread_mutex_init(&mutex,NULL);//四個賣家生產蘋果for(int i = 0;i<4;i++){pthread_create(&tid,NULL,product,(void *)i);}//四個買家買蘋果for(int i = 0;i<4;i++){pthread_create(&tid,NULL,consumer,(void *)i);}//等待thread標識的線程終止,防止僵尸進程產生pthread_join(tid,NULL);//銷毀所有資源pthread_cond_destroy(&full);pthread_cond_destroy(&empty);pthread_mutex_destroy(&mutex);
}

如果對于互斥量含義尚不清楚,建議閱讀Linux/UNIX系統編程手冊

pthread_mutex_t
pthread_mutex_init
pthread_mutex_lock
pthread_mutex_unlock
pthread_mutex_destroy

模型采取Linux/UNIX系統編程手冊
這個模型很好,也把概念講清楚了,加了中文注釋

生產者

s = pthread_mutex_lock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_lock");avail++;        /*這是一個原子操作 */s = pthread_mutex_unlock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_unlock");s = pthread_cond_signal(&cond);         /* 喚醒消費者 */
if (s != 0)errExitEN(s, "pthread_cond_signal");

消費者

s = pthread_mutex_lock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_lock");while (avail == 0){           s = pthread_cond_wait(&cond, &mtx);if (s != 0)errExitEN(s, "pthread_cond_wait");
}

完整代碼

#include <time.h>
#include <pthread.h>
#include "tlpi_hdr.h"static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;static int avail = 0;static void *
threadFunc(void *arg)
{int cnt = atoi((char *) arg);int s, j;for (j = 0; j < cnt; j++) {sleep(1);/* Code to produce a unit omitted */s = pthread_mutex_lock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_lock");avail++;        /* Let consumer know another unit is available */s = pthread_mutex_unlock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_unlock");s = pthread_cond_signal(&cond);         /* Wake sleeping consumer */if (s != 0)errExitEN(s, "pthread_cond_signal");}return NULL;
}int
main(int argc, char *argv[])
{pthread_t tid;int s, j;int totRequired;            /* Total number of units that all threadswill produce */int numConsumed;            /* Total units so far consumed */Boolean done;time_t t;t = time(NULL);/* Create all threads */totRequired = 0;for (j = 1; j < argc; j++) {totRequired += atoi(argv[j]);s = pthread_create(&tid, NULL, threadFunc, argv[j]);if (s != 0)errExitEN(s, "pthread_create");}/* Loop to consume available units */numConsumed = 0;done = FALSE;for (;;) {s = pthread_mutex_lock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_lock");while (avail == 0) {            /* Wait for something to consume */s = pthread_cond_wait(&cond, &mtx);if (s != 0)errExitEN(s, "pthread_cond_wait");}/* At this point, 'mtx' is locked... */while (avail > 0) {             /* Consume all available units *//* Do something with produced unit */numConsumed ++;avail--;printf("T=%ld: numConsumed=%d\n", (long) (time(NULL) - t),numConsumed);done = numConsumed >= totRequired;}s = pthread_mutex_unlock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_unlock");if (done)break;/* Perhaps do other work here that does not require mutex lock */}exit(EXIT_SUCCESS);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382710.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382710.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382710.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux之信號

信號&#xff1a;在生活中&#xff0c;我們遇到過不同種類的信號&#xff0c;比如&#xff1a;&#xff08;交通信號&#xff0c;乃至某個人的表情&#xff0c;動作等帶給你不同的信號&#xff09;然而&#xff0c;在我們的linux下&#xff0c;我們最熟悉的就是&#xff0c;當遇…

視頻解析有感,在解析 iqiyi與qq視頻的時候,記錄一些發現

最近對iqiyi與qq視頻解析發現&#xff0c;兩個網站的解析流程&#xff0c;尤其是反解析措施 各有特點&#xff0c;簡單記錄一下 先說iqiyi&#xff0c; 瀏覽器模擬移動端可以拿到視頻的mp4鏈接&#xff0c;這個不多說。 iqiyiPC端瀏覽器獲取 ts過程&#xff1a; a.iqiyi一次性…

C語言atoi函數的用法

#include < stdlib.h > int atoi(const char *nptr);用法&#xff1a;將字符串里的數字字符轉化為整形數。返回整形值。 注意&#xff1a;轉化時跳過前面的空格字符&#xff0c;直到遇上數字或正負符號才開始做轉換&#xff0c;而再遇到非數字或字符串結束時(’/0’)才…

[Linux]繼續探究mysleep函數(競態條件)

之前我們探究過mysleep的簡單用法&#xff0c;我們實現的代碼是這樣的&#xff1a; #include<stdio.h> #include<signal.h>void myhandler(int sig) {}unsigned int mysleep(unsigned int timeout) {struct sigaction act,oact;act.sa_handler myhandler;sigempt…

C語言的atoi和C++的to_string

to_stringint to string將其他型轉換成字符串型atoiascii to integer是把字符串轉換成整型數的一個函數 to_string #include <iostream> // std::cout #include <string> // std::string, std::to_stringint main () {std::string perfect std::to_string…

ubuntu 升級python3.5到python3.7,并升級pip3

1, 下載python3.7.tgz 文件&#xff0c;解壓&#xff0c; 2. 編譯安裝 3. 刪除 /usr/bin 目錄下的 pip3, python3 4. 建立新的軟連接&#xff1a; #添加python3的軟鏈接ln -s /usr/local/python3/bin/python3.7 /usr/bin/python3#添加 pip3 的軟鏈接ln -s /usr/local/python3/b…

[Linux]死鎖

死鎖是指多個進程在運行過程中因爭奪資源而造成的一種僵局&#xff0c;當進程處于這種僵持狀態時&#xff0c;若無外力作用&#xff0c;它們都將無法再向前推進。之前信號量的時候我們知道&#xff0c;如果多個進程等待&#xff0c;主要體現在占有鎖的問題上。死鎖也可以被定義…

Python安裝第三方模塊總結 轉載的

轉自 https://www.jellythink.com/archives/541

[C++]vector創建二維數組

c.resize(n);將c重置為大小為n個元素向量&#xff0c;如果n比原來的元素多&#xff0c;則多出的元素常被初始化為0//節選《面向對象的程序設計》杜茂青 int N5, M6; vector<vector<int> > Matrix(N); for(int i 0; i< Matrix.size(); i){ Matrix[i].resize(M…

[Linux]線程安全和可重入函數

線程安全&#xff1a;一個函數被稱為線程安全的&#xff0c;當且僅當被多個并發進程反復調用時&#xff0c;它會一直產生正確的結果。如果一個函數不是線程安全的&#xff0c;我們就說它是線程不安全的。 重入&#xff1a;函數被不同的控制流程調用,有可能在第一次調用還沒返回…

[Linux]信號量

信號量是一個計數器&#xff0c;用于為多個進程提供對共享數據對象的訪問。 在信號量上只有三種操作可以進行&#xff0c;初始化、遞增和增加&#xff0c;這三種操作都是原子操作。遞減操作可以用于阻塞一個進程&#xff0c;增加操作用于解除阻塞一個進程。 為了獲得共享資源…

Linux VIM 程序中有游離的‘\357’ ‘\274’錯誤

gcc date.cpp -o date -lstdc date.cpp:18:20: 錯誤&#xff1a;程序中有游離的‘\357’date.Showdata()&#xfffd;&#xfffd;&#xfffd;^ date.cpp:18:21: 錯誤&#xff1a;程序中有游離的‘\274’date.Showdata()&#xfffd;&#xfffd;&#xfffd;^ date.cpp:18:22…

[Linux]關于SIGCHLD

之前我們就學過&#xff0c;關于wait和waitpid來處理僵尸進程&#xff0c;父進程等待子進程結束后自己才退出&#xff0c;這樣的方法有倆種方式&#xff0c;一種是父進程死死的等子進程退出&#xff0c;也就是使用阻塞的方式等待子進程退出&#xff0c;另一種方式是通過非阻塞的…

C語言思維導圖

本人能力有限&#xff0c;知識點難免概括不全&#xff0c;如有錯誤歡迎指正

轉載一篇關于curl的文章

轉載一篇關于curl的文章 http://www.360doc.com/content/16/0107/15/18578054_526158476.shtml

[Linux]vi/vim下添加多行注釋和取消注釋

添加注釋&#xff08;Centos&#xff09;&#xff1a; 在命令行模式下按ctrlV進入 visual block模式&#xff08;可視化模式&#xff09; 選中你需要注釋的行&#xff0c;再按大寫的I&#xff0c;輸入//&#xff0c;最后按倆下esc即可。 如果想讓前進tab個位&#xff0c;則可在…

pthread和互斥量條件變量函數意義速查表

數據類型 pthread_t 線程 互斥量和條件變量

[Linux]共享內存

共享內存是UNIX提供的進程間通信手段中速度最快的一種&#xff0c;也是最快的IPC形式。為什么是最快的呢&#xff0c;因為數據不需要在客戶進程和服務器進程之間復制&#xff0c;所以是最快的一種IPC。這是虛存中由多個進程共享的一個公共內存塊。 兩個不同進程A、B共享內存的…

僵尸進程的產生,危害和解決方案

概念 僵死狀態&#xff08;Zombies&#xff09;是一個比較特殊的狀態。 當進程退出并且父進程沒有讀取到子進程退出的返回代碼時就會產生僵尸進程。僵尸進程會以終止狀態保持在進程表中&#xff0c;并且會一直在等待父進程讀取退出狀態代碼。所以&#xff0c;只要子進程退出&…

CString string 轉換

https://www.cnblogs.com/HappyEDay/p/7016162.html