Linux线程(四)
Linux線程(四)
文章目錄
- Linux線程(四)
- 一、線程同步
- 二、生產(chǎn)者消費者模型
一、線程同步
-
1.條件變量
-
當(dāng)一個線程互斥的訪問某個變量時,他可能發(fā)現(xiàn)在其他線程改變狀態(tài)之前,他自己什么都做不了
-
例如一個線程訪問隊列時,發(fā)現(xiàn)隊列為空,它只能等待,直到其他線程講一個節(jié)點添加到隊列中。這種情況就要用到條件變量
-
2.同步概念與竟態(tài)條件
-
同步:在保證數(shù)據(jù)安全的情況下,讓線程能夠按照某種特定的順序訪問臨界資源,從而有效的避免極餓問題,叫同步
-
競態(tài)條件:因為時許問題而導(dǎo)致出現(xiàn)異常,稱為競態(tài)條件。
-
3.條件變量的初始化
-
方法一:靜態(tài)初始化
- 方法二:動態(tài)初始化
- 功能:初始化一個條件變量
- 參數(shù):
- 4.pthread_cond_destroy函數(shù)
- 功能:銷毀一個條件變量
- 參數(shù):pthread_cond_t *cond:待銷毀的條件變量
- 5.pthread_cond_wait函數(shù)
- 功能:等待條件的滿足
- 參數(shù):
- 先釋放鎖(必須是原子的)
- 等待條件的滿足(必須是原子的)
- 重新獲取鎖,繼續(xù)執(zhí)行
- 6.pthread_cond_broadcast和pthread_cond_signal函數(shù)
- 功能:喚醒等待
例子:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h>pthread_cond_t cond; pthread_mutex_t mutex;void *r1( void *arg ) {while ( 1 ){pthread_cond_wait(&cond, &mutex);printf("活動\n");} } void *r2(void *arg ) {while ( 1 ) {pthread_cond_signal(&cond);sleep(1);} } int main( void ) {pthread_t t1, t2;pthread_cond_init(&cond, NULL);pthread_mutex_init(&mutex, NULL);pthread_create(&t1, NULL, r1, NULL);pthread_create(&t2, NULL, r2, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond); }- 7.為什么pthread_cond_wait函數(shù)需要用到互斥量
- 條件等待是線程同步的一種手段,如果只有一個線程,條件不滿足,一直等下去都會不滿足,所以必須要有一個線程通過某些操作,改變共享變量,使原來不滿足的條件的到滿足,并且友好的通知正在等待條件上的線程
- 條件不會無緣無故的突然變得滿足了,必然會牽扯到共享數(shù)據(jù)的變化,所以需要用互斥鎖來保護。沒有互斥鎖就無法安全的獲取和修改共享數(shù)據(jù)
- 按照上面的說法,我們設(shè)計出如下的代碼:先上鎖,發(fā)現(xiàn)條件不滿足,解鎖,然后等待在條件變量上不就行了,如下代碼:
-
由于解鎖和等待不是原子操作。調(diào)用解鎖后,pthread_cond_wait之前,如果已經(jīng)有其他的線程獲取到互斥量,摒棄條件滿足,發(fā)送了信號,那么pthread_cond_wait將會錯過這個信號,可能會導(dǎo)致線程永遠阻塞在pthread_cond_wait這里。
-
所以解鎖操作必須是原子操作
-
進入pthread_cond_wait這個函數(shù)后,會去看條件變量是否等于0,如果等于0,就把互斥量置為1,直到pthread_cond_wait返回,把條件變量改成1,把互斥量恢復(fù)成原樣
-
8.條件變量使用規(guī)范
-
等待條件的代碼:
- 給條件發(fā)送信號代碼:
二、生產(chǎn)者消費者模型
- 1.為什要使用生產(chǎn)者消費者模型 ?
生產(chǎn)者消費者模式就是通過一個容器來解決生產(chǎn)者和消費者的強耦合問題。生產(chǎn)者和消費者彼此之間不直接通訊,而通過阻塞隊列來進行通訊,所以生產(chǎn)者生產(chǎn)完數(shù)據(jù)之后不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產(chǎn)者要數(shù)據(jù),而是直接從阻塞隊列里取,阻塞隊列就相當(dāng)于一個緩沖區(qū),平衡了生產(chǎn)者和消費者的處理能力。這個阻塞隊列就是用來給生產(chǎn)者和消費者解耦的
- 2.生產(chǎn)者消費者模型的優(yōu)點
- 解耦
- 支持并發(fā)
- 支持忙閑不均問題
- 3.生產(chǎn)者消費者模型流程圖:
- 基于BlockingQueue的生產(chǎn)者消費者模型 BlockingQueue 在多線程編程中阻塞隊列(Blocking Queue)是一種常用于實現(xiàn)生產(chǎn)者和消費者模型的數(shù)據(jù)結(jié)構(gòu)。
- 其與普通的隊列區(qū)別在于,當(dāng)隊列為空時,從隊列獲取元素的操作將會被阻塞,直到隊列中被放入了元素;當(dāng)隊列滿時,往隊列里存放元素的操作也會被阻塞,直到有元素被從隊列中取出
例子:單生產(chǎn)者單消費者代碼:
#include <iostream> #include <queue> #include <stdlib.h> #include <pthread.h> #define NUM 8class BlockQueue{ private:std::queue<int> q;int cap;pthread_mutex_t lock;pthread_cond_t full;pthread_cond_t empty;private:void LockQueue(){pthread_mutex_lock(&lock);} void UnLockQueue(){pthread_mutex_unlock(&lock);} void ProductWait(){pthread_cond_wait(&full, &lock);} void ConsumeWait(){pthread_cond_wait(&empty, &lock);} void NotifyProduct(){pthread_cond_signal(&full);} void NotifyConsume(){pthread_cond_signal(&empty);} bool IsEmpty(){return ( q.size() == 0 ? true : false );} bool IsFull(){return ( q.size() == cap ? true : false );}public:BlockQueue(int _cap = NUM):cap(_cap){pthread_mutex_init(&lock, NULL);pthread_cond_init(&full, NULL);pthread_cond_init(&empty, NULL);} void PushData(const int &data){LockQueue();while(IsFull()){NotifyConsume();std::cout << "queue full, notify consume data, product stop." << std::endl;ProductWait();} q.push(data);// NotifyConsume();UnLockQueue();} void PopData(int &data){LockQueue();while(IsEmpty()){NotifyProduct();std::cout << "queue empty, notify product data, consume stop." <<std::endl;ConsumeWait();} data = q.front();q.pop();// NotifyProduct();UnLockQueue();} ~BlockQueue(){pthread_mutex_destroy(&lock);pthread_cond_destroy(&full);pthread_cond_destroy(&empty);} };void *consumer(void *arg) {BlockQueue *bqp = (BlockQueue*)arg;int data;for( ; ; ){bqp->PopData(data);std::cout << "Consume data done : " << data << std::endl;} } //more faster void *producter(void *arg) {BlockQueue *bqp = (BlockQueue*)arg;srand((unsigned long)time(NULL));for( ; ; ){int data = rand() % 1024;bqp->PushData(data);std::cout << "Prodoct data done: " << data << std::endl;// sleep(1);} }int main() {BlockQueue bq;pthread_t c,p;pthread_create(&c, NULL, consumer, (void*)&bq);pthread_create(&p, NULL, producter, (void*)&bq);pthread_join(c, NULL);pthread_join(p, NULL);return 0; }總結(jié)
以上是生活随笔為你收集整理的Linux线程(四)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux线程(三)
- 下一篇: Linux线程(五)