一、生產者-消費者模式的簡介
在實際的軟體開發過程中,我們將產生資料的模組稱為生產者,處理資料的模組成為消費者。但僅有這兩者還不夠成為乙個生產者-消費者模式,還需要有乙個緩衝區(一段記憶體區域)作為中介,生產者產生的資料放入緩衝區,消費者從緩衝區讀取資料並處理。(注:上述所說的模組是廣義的,可以是類,函式,執行緒,程序等)
我們可以將這二者之間的關係圖表示出來:
總結:我們用3-2-1的方法來簡單描述乙個生產者-消費者模式,3代表有三種關係:生產者-生產者,消費者-消費者,生產者-消費者;2代表兩個角色:生產者,消費者;1代表乙個交易場所:緩衝區
二、生產者-消費者模式之間的關係
模擬實現生產者-消費者模式之前,我們需要先捋清除這之間的關係:
生產者-生產者:很明顯,這兩者之間必定是一種競爭關係,也就是說乙個生產者往緩衝區放資料時另乙個生產者就不能去訪問這塊空間
消費者-消費者:同樣,兩個消費者之間也是競爭的關係,這就好比兩個人同時看中一件商品時,他們之間就是一種競爭的關係
生產者-消費者:生產者與消費者之間其實是一種同步與互斥的關係,假設只有乙個生產者乙個消費者時,只有生產者放入資料後消費者才能讀取,消費者拿到資料後生產者才去生產,這就是一種同步;但當生產者生產資料的時候消費者就不能從緩衝區拿資料,或者消費者讀資料的時候生產者就不能往緩衝區裡寫資料,否則很可能會導致兩者都存/取資料失敗,產生二義性問題。
三、如何實現單生產者-單消費者模型
對於單生產者-單消費者模式來說,我們可以用單鏈表來模擬乙個交易場所,生產資料就相當於往鍊錶裡面插入結點,消費者讀取資料就相當於刪除鍊錶結點(這裡我採用的是頭插頭刪的方式,當然也可以用尾插、尾刪的方式實現)
既然已經確定了生產場所,其次我們要考慮到如何才能讓這二者時間實現同步與互斥。多執行緒程式設計中提到了「條件變數(condition variable)」,在此,我們先給出幾個函式:
初始化和銷毀:
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
pthread_cond_t cond = pthread_cond_initializer;
//attr引數為null,表示預設屬性。如果condition variable是靜態分配的,也可以用巨集定義pthead_cond_initializer初始化,相當於用pthread_cond_init函式初始化並且attr引數為null。
操作函式:
int pthread_cond_broadcast(pthread_cond_t *cond);
//一次喚醒在某個condition variable上等待的所有執行緒
int pthread_cond_signal(pthread_cond_t *cond);
//一次喚醒在某個condition variable上等待的另乙個執行緒
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,
const
struct timespec *restrict abstime);
//pthread_cond_timedwait函式還有乙個額外的引數來設定等待超時,如果到達了abstime所指定的時刻仍然沒有別的執行緒來喚醒當前執行緒,就返回etimedout。
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
//呼叫pthread_cond_wait在乙個condition variable上阻塞等待,這個函式做以下三步操作:
1.釋放mutex
2.阻塞等待
3.當被喚醒時,重新獲得mutex並返回
我們可以利用條件變數中的相關函式來模擬實現,當生產者執行緒生產資料時消費者執行緒就wait,當被喚醒後,此時鍊錶已經有資料(消費者等待成功),拿走結點;消費者讀取資料的過程中生產者在wait,等到消費者讀取資料完之後被喚醒,然後繼續往緩衝區寫入資料(迴圈………),等待與被喚醒的過程就可以利用上述的pthread_cond_wait和pthread_cond_signal函式實現。
具體**如下:
pthread_mutex_t mylock = pthread_mutex_initializer;
pthread_cond_t mycond = pthread_cond_initializer;
typedef struct _node
node,*pnode,**ppnode;
pnode alloc_node(int data)
_n->
data
=data;
_n->next =
null;
return _n;
} void initlist(ppnode _h)
void pushfront(pnode _h,int data)
void delnode(pnode node)
void popfront(pnode _h,int*
data)
pnode del = _h->next;
_h->next = del->next;
*data
= del->
data;
delnode(del);
} void destory(pnode _h)
delnode(_h);
} void show(pnode _h)
printf("\n");
} void
* thread_product(void
* arg)
} void
* thread_consumer(void
* arg)
popfront(node,&
data);
pthread_mutex_unlock(&mylock);
printf("consumer:%d \n",data);
} } void test_list(pnode head)
int data
=0;
for(; i>=
0; i--)
destory(head);
show(head);
} int main()
NSCondition 多執行緒解決生產者消費者問題
import viewcontroller.h inte ce viewcontroller 資料緩衝區 property strong,nonatomic nsmutablearray products 執行緒鎖 property strong,nonatomic nscondition cond...
linux多執行緒實現生產者消費者
1.初始化 條件變數採用的資料型別是pthread cond t,在使用之前必須要進行初始化,這包括兩種方式 include include include 條件變數生產者和消費者 pthread cond t condc,condp pthread mutex t the mutex unsign...
Linux多執行緒 生產者消費者
生產者消費者問題 這是乙個非常經典的多執行緒題目,題目大意如下 有乙個生產者在生產產品,這些產品將提供給若干個消費者去消費,為了使生產者和消費者能併發執行,在兩者之間設定乙個有多個緩衝區的緩衝池,生產者將它生產的產品放入乙個緩衝區中,消費者可以從緩衝區中取走產品進行消費,所有生產者和消費者都是非同步...