linux---生產者和消費者模型

生產者消費者模式就是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞隊列來進行通訊,所以生產者生產完數據之后不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列里取,阻塞隊列就相當于一個緩沖區,平衡了生產者和消費者的處理能力。這個阻塞隊列就是用來給生產者和消費者解耦的。

一、堵塞隊列

(1)三種關系

生產者vs生產者:互斥(加鎖)

消費者vs消費者:互斥(加鎖)

生產者vs消費者:互斥和同步(加鎖和條件變量)

(2)代碼實現

Makefile

test:Main.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f test

BlockQueue.hpp

#include<iostream>
#include<queue>
#include<unistd.h>
#define M 10
template<class T>
class BlockQueue{
public:
BlockQueue(T cap=M)
:_capacity(M)
{pthread_mutex_init(&_mutex,nullptr);pthread_cond_init(&_pcond,nullptr);pthread_cond_init(&_ccond,nullptr);}bool IsFull()
{return q.size()==_capacity;
}
bool empty()
{return q.size()==0;
}void Push( T in)
{pthread_mutex_lock(&_mutex);//if(!IsFull())//可能出現偽喚醒while(IsFull())//健壯性{pthread_cond_wait(&_pcond,&_mutex);}q.push(in);std::cout<<"push:"<<in<<std::endl;sleep(1);pthread_cond_signal(&_ccond);pthread_mutex_unlock(&_mutex);
}void Pop()
{pthread_mutex_lock(&_mutex);while(empty())//if(!empty())//如果這里使用if判斷的話,可能出現偽喚醒問題。{pthread_cond_wait(&_ccond,&_mutex);}auto n=q.front();std::cout<<"pop:"<<n<<std::endl;sleep(1);q.pop();pthread_cond_signal(&_pcond);pthread_mutex_unlock(&_mutex);}~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_pcond);
pthread_cond_destroy(&_ccond);
}private:pthread_mutex_t _mutex;pthread_cond_t _pcond;pthread_cond_t _ccond;int _capacity=M;std::queue<T> q;};

Main.cc?

#include<pthread.h>
#include"BlockQueue.hpp"
#include<iostream>
void* consumer(void* argv)
{BlockQueue<int>* q=static_cast<BlockQueue<int>*>(argv);int i=0;while(true){  q->Pop();}return nullptr;
}
void * productor(void* argv)
{BlockQueue<int>* q=static_cast<BlockQueue<int>*>(argv);while(true){int data=rand()%10+1;q->Push(data);}
return nullptr;
}int main()
{srand((unsigned)time(NULL)^getpid()^pthread_self());pthread_t c,p;BlockQueue<int>* bq=new BlockQueue<int>();pthread_create(&c,nullptr,consumer,bq);pthread_create(&p,nullptr,productor,bq);pthread_join(c,nullptr);pthread_join(p,nullptr);return 0;
}

(3)總結

以上是單生產和單消費,對于多生產和多消費也是可以的,因為是同一個隊列,同一把鎖,同一把鎖就決定了,生產者和生產者,消費者和消費者之間就是互斥的,生產者和消費者的條件變量提供了同步。

隊列中的數據也可以是任務,堵塞隊列可以實現高并發高效率,在與每個線程都拿到了自己的任務

并且處理任務,處理任務也是需要時間的,這個決定了,每個線程拿到任務都在跑自己的任務代碼,實現高并發。同時條件變量讓生產者和消費者進行同步,保證了安全性。

1.消費者和生產者調度優先級

如果消費者線程先調度,隊列為空,消費者就會在條件變量下進行等待,等生產者生產商品了,就會喚醒消費者進行消費。

2.如何控制生產消費的節奏

我們可以通過sleep控制。比如消費者消費進行休眠的話,可以給生產者足夠的時間進行生產

3.偽喚醒

如果用if來判斷隊列為空可能會出現偽喚醒,有些線程處于等待堵塞,競爭鎖的狀態,一旦隊列為空而線程競爭到了鎖就會出現隊列為空依然進行pop的現象。

while(true)可以提供檢查,if判斷可能有風險。


環形隊列

(1)POSIX信號量

posix和SystemV信號量作用相同,都是用于同步操作,達到無沖突的訪問共享資源目的。 但POSIX可以用于線程間同步.

快速認識接口:

(1)初始化

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

參數: pshared:0表示線程間共享,非零表示進程間共享value:信號量初始值

(2)銷毀

int sem_destroy(sem_t *sem);
?

(3)等待

功能:等待信號量,會將信號量的值減1

int sem_wait(sem_t *sem);//p()
?

(3)通知

功能:發布信號量,表示資源使用完畢,可以歸還資源了。將信號量值加1。int sem_post(sem_t *sem);//V()
?

三種關系

(2)對于環形隊列,生產者和消費者就有兩種場景會指向同一個位置。要么為空,要么為滿,其他情況不會指向同一個位置。

1.如果隊列為空,只能讓生產者先生產,消費者不可以消費---------互斥

2.如果隊列為滿,只能讓消費者先消費,然后到生產者生產---------同步

3.其余情況,消費者都是在生產者后面的,兩個位置不同,即使pop和push同時進行,也是安全的,這個就是多線程高并發可以進入臨界區的原因。

如何實現多線程中的生產者和生產者,消費者和消費者的互斥問題,對于循環隊列,我們要定義兩把鎖,一個是push隊列的鎖,一個是pop隊列的鎖。pv操作是原子性的,讓生產者和消費者進行同步其中又可以體現互斥。

代碼實現

makefile

ringtest:Main.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f ringtest

Main.cc

#include<iostream>
#include<pthread.h>
#include"RingQueue.hpp"
#include<pthread.h>void* producter(void* args)
{while(true){ RingQueue<int>* rq=static_cast<RingQueue<int>*>(args);int n=1;n=rand()%3+1;rq->Push(n);}}
void* consumer(void* argv)
{while(true)
{RingQueue<int>* q=static_cast<RingQueue<int>*>(argv);int date=0;q->Pop(&date);}}int main()
{srand(time(nullptr));pthread_t p,c;
pthread_mutex_t pm,cm;LockGuard pmutex(&pm),cmutex(&cm);RingQueue<int> ringqueue(cmutex,pmutex);
pthread_create(&p,nullptr,consumer,&ringqueue);
pthread_create(&c,nullptr,producter,&ringqueue);pthread_join(p,nullptr);pthread_join(c,nullptr);return 0;
}

RingQueue.hpp?

#include<vector>
#include<iostream>
#include"LockGuard.hpp"
#include<unistd.h>
const int Size =10;
template<class T>
class RingQueue{
private:void P(sem_t& sem){sem_wait(&sem);}void V(sem_t& sem){sem_post(&sem);}
public:
RingQueue(LockGuard c,LockGuard p,int s=Size)
:size(s),pmutex(p),cmutex(c),q(s),ppose(0),cpose(0)
{
sem_init(&psem,0,size);
sem_init(&csem,0,0);}// 生產
void Push(const T& in)
{// 先加鎖,還是先申請信號量?先申請信號量,效率高。申請到資源的線程,只有競爭到鎖,就可以生產了。P(psem);{pmutex;q[ppose] = in;std::cout<<"生產:"<<in<<std::endl;ppose++;ppose %=size;}V(csem);
}
void Pop(T* out)
{P(csem);{cmutex;*out = q[cpose];sleep(1);std::cout<<"消費:"<<*out<<std::endl;cpose++;cpose %=size;}V(psem);}
~RingQueue()
{sem_destroy(&psem);sem_destroy(&csem);
}private:int size;std::vector<int> q;int ppose;//生產者位置int cpose;//消費者位置sem_t psem;//生產者信號量sem_t csem;//消費者信號量LockGuard pmutex;LockGuard cmutex;};
#pragma once
#include<pthread.h>
#include <semaphore.h>
class Mutex{
public:Mutex(pthread_mutex_t* mutex):_Mutex(mutex){pthread_mutex_init(_Mutex,nullptr);}void Lock(){pthread_mutex_lock(_Mutex);}void unlock(){pthread_mutex_unlock(_Mutex);}~Mutex(){pthread_mutex_destroy(_Mutex);}private:pthread_mutex_t* _Mutex;
};class LockGuard{
public:LockGuard(pthread_mutex_t* lock):mutex(lock){mutex.Lock();}~LockGuard(){mutex.unlock();}private:Mutex mutex;};

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

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

相關文章

2024年海南省三支一扶報名指南,照片要求

2024年海南省三支一扶報名指南&#xff0c;照片要求 一、考試時間安排&#xff1a; 報名時間&#xff1a;6月1日8:00至6月7日18:00 準考證打印時間&#xff1a;6月17日8:00 考試時間&#xff1a;6月22日 二、招聘人數 海南省計劃招募390名高校畢業生

STM32_IIC

1、IIC簡介 I2C&#xff0c;即Inter IC Bus。是由Philips公司開發的一種串行通用數據總線&#xff0c;主要用于近距離、低速的芯片之間的通信&#xff1b;有兩根通信線&#xff1a;SCL&#xff08;Serial Clock&#xff09;用于通信雙方時鐘的同步、SDA&#xff08;Serial Data…

JVM之【執行引擎】

執行引擎 執行引擎是JVM的核心組件之一&#xff0c;它負責將Java字節碼文件轉換為機器指令并執行。這一過程涉及多個組成部分&#xff0c;各部分協同工作來完成字節碼到機器指令的轉換和執行。以下是執行引擎的主要組成部分及其作用&#xff1a; 1. 解釋器&#xff08;Interp…

vue.js框架快速入門

Vue.js是一個漸進式JavaScript框架&#xff0c;用于構建用戶界面和單頁應用程序。以下是Vue.js快速入門的基本步驟和概念&#xff1a; 1. 環境準備 確保你的計算機上安裝了Node.js&#xff0c;它包括npm&#xff08;Node Package Manager&#xff09;&#xff0c;用于管理項目…

友善RK3399v2平臺利用rkmpp實現硬件編解碼加速

測試VPU 編譯mpp sudo apt update sudo apt install gcc g cmake make cd ~ git clone https://github.com/rockchip-linux/mpp.git cd mpp/build/linux/aarch64/ sed -i s/aarch64-linux-gnu-gcc/gcc/g ./arm.linux.cross.cmake sed -i s/aarch64-linux-gnu-g/g/g ./arm.lin…

如何學習ai agent?

如何學習Agent&#xff0c;推薦閱讀《動手做AI Agent》這本書。 推薦理由&#xff1a; 1&#xff1a;一本書能夠全方位了解并探索Agent的奧秘&#xff01; &#xff08;1&#xff09;Agent的發展進程。 &#xff08;2&#xff09;可以幫我們做哪些事&#xff1a;自動辦公&am…

TypeScript 中的迭代器和生成器

1. 迭代器 迭代器是一種對象&#xff0c;它提供了一種統一的方式來訪問集合中的元素&#xff0c;而不暴露集合的內部結構。在 TypeScript 中&#xff0c;迭代器通過實現 Iterator 接口來定義。 interface Iterator<T> {next(): IteratorResult<T>; }interface It…

Liunx登錄時相關bash配置文件(登錄腳本)

profile類的文件&#xff1a;設定環境變量&#xff0c;運行命令或腳本 bashrc類的文件&#xff1a;定義命令別名 全局配置&#xff1a; /etc/profile /etc/profile.d/*.sh /etc/bashrc 個人配置文件: ~/.bash_profile ~/.bashrc 用戶登錄時加載bash配置文件的過程&#xff0c;…

碼隨想錄算法訓練營第二十四天| 77. 組合

77. 組合 - 力扣&#xff08;LeetCode&#xff09; class Solution {ArrayList<Integer> path new ArrayList<>();ArrayList<List<Integer>> result new ArrayList<>();public List<List<Integer>> combine(int n, int k) {if(n &…

升級Jenkins從2.263.3到2.440.2

升級Jenkins從2.263.3到2.440.2 ###任何一次升級前&#xff0c;先做整體備份&#xff0c;同時最好對plugins目錄和config.xml單獨備份。 ###對于任何一次插件安裝&#xff0c;務必安裝前先備份當前的plugins目錄&#xff0c;這是血的教訓。升級過程 1、 升級2.263.3到2.263.4…

15-通過JS代碼處理窗口滾動條

selenium并不是萬能的&#xff0c;頁面上有些操作無法實現時&#xff0c;就需要借助JS代碼來完成了。selenium提供了一個方法&#xff1a;execute_script()&#xff0c;可以執行JS腳本代碼。 比如&#xff1a;當頁面上的元素超過一屏后&#xff0c;想操作屏幕下方的元素&#x…

MyBatis查詢功能

MyBatis的各種查詢功能 1、若查詢出的數據只有一條 &#xff08;1)可以通過實體類對象或者集合接收 (2)可以通過List集合接收 (3&#xff09;可以通過map集合接收 結果&#xff1a;{password123456, sex女, id8, age22, email1234qq.com, usernameadmin4} 2、若查詢出來的數據有…

[leetcode hot 150]第一百零八題,將有序數組轉換為二叉搜索樹

題目&#xff1a;給你一個整數數組 nums &#xff0c;其中元素已經按 升序 排列&#xff0c;請你將其轉換為一棵 平衡二叉搜索樹。 給定一個有序的整數數組,我們需要構建一棵平衡的二叉搜索樹。平衡二叉樹是指任意一個節點的左右子樹的高度差不超過1。 由于給定的數組是有序的…

阿里云計算學習筆記(一)

運維管理 運維管理&#xff08;Operation and Maintenance Management, 簡稱O&M管理&#xff09;是指通過科學的管理方法和技術手段&#xff0c;對IT系統和基礎設施進行監控、維護、優化和保障&#xff0c;以確保系統的高可用性、穩定性、安全性和性能。運維管理涵蓋了硬件…

Prime1 - 提權的另一種解法,徹底搞懂OpenSSL解密滲透提權,超強思路版。

提權枚舉 現在我們直接從低權限用戶開始&#xff1b;我們先按照提權步驟&#xff0c;簡單的系統枚舉 雖然我們知道可以利用系統版本低進行內核提權&#xff0c;內核提權雖然比較快比較方便&#xff0c;但也比較暴力&#xff0c;缺點非常明顯&#xff1b;很容易導致系統服務中…

【云原生】Kubernetes----POD控制器

目錄 引言 一、Pod控制器概述 二、Pod控制器的種類 &#xff08;一&#xff09;ReplicaSet &#xff08;二&#xff09;Deployment &#xff08;三&#xff09;StatefulSet &#xff08;四&#xff09;DaemonSet &#xff08;五&#xff09;Job 三、使用POD控制器 &a…

【Seafile】Seafile容器版文件刪除后存儲空間不釋放問題解決

Seafile是一款非常優秀的網盤系統&#xff0c;我們可以根據官方文檔&#xff0c;在本地虛擬機研究Seafile免費版的安裝和使用&#xff0c;安裝建議采用使用docker容器的方式。 不過在使用過程中&#xff0c;剛接觸的小伙伴可能會遇到這樣的問題&#xff1a; 刪除網盤里面的文…

數據賦能(106)——方法論:描述模式與AI——批量處理

在一系列相似的主題內容進行編寫時&#xff0c;可以采用批處理的方式。主要步驟如下&#xff1a; 1、確定主題內容模式。如&#xff1a;各個主題的概述中&#xff0c;包括如下內容模式項目&#xff1a;工作主要目的、工作重要性、工作核心內容、工作本質 2、確定模式的各項內…

C++設計模式-狀態模式

文章目錄 28. 狀態模式 運行在VS2022&#xff0c;x86&#xff0c;Debug下。 28. 狀態模式 狀態模式讓一個對象的行為隨著內部狀態的改變而改變&#xff0c;而該對象也像換了類一樣。應用&#xff1a;如在游戲開發中&#xff0c;游戲有不同場景&#xff0c;如主菜單、開始、戰斗…

在leafet上畫圓、多邊形、線、矩形

在leaflet上畫圓、多邊形、線、矩形 <template><div id"map" class"map"></div> </template><script> import L from leaflet; export default {data () {return {myGroup: ,};},mounted () {this.initMaps()this.huizhiro…