1. 程式人生 > >muduo網路庫學習筆記(5):執行緒池的實現

muduo網路庫學習筆記(5):執行緒池的實現

瞭解生產者-消費者問題

生產者-消費者問題也被稱為有界緩衝區問題,兩個程序/執行緒共享一個公共的固定大小的緩衝區。其中一個是生產者,將資訊放入緩衝區;另一個是消費者,從緩衝區中取出資訊。

問題在於當緩衝區已滿,而此時生產者還想向其中放入一個新的資料項的情況。其解決方法就是讓生產者休眠,待消費者從緩衝區中取出一個或多個數據項時再喚醒它。同樣地,當消費者試圖從緩衝區中取資料而發現緩衝區為空時,消費者就休眠,直到生產者向其中放入一些資料時再將其喚醒。

// 以下程式碼只是對生產者-消費者問題的大致描述
// 因為對count的訪問未加限制,可能會出現競爭條件問題

#define N 100   // 緩衝區的槽數目
int count = 0; // 緩衝區中的資料項的數目 // 生產者 void producer(void) { int item; while(TRUE){ item = produce_item(); if(count == N) sleep(); insert_item(item); count = count + 1; if(count == 1) wakeup(consumer); } } // 消費者 void consumer(void) { int item; while
(TRUE){ if(count == 0) sleep(); item = remove_item(); count = count - 1; if(count == N - 1) wakeup(producer); consume_item(item); } }

執行緒池問題本質上也是一個生產者-消費者問題

外部執行緒可以向執行緒池中的任務佇列新增任務,相當於“生產者”;一旦任務佇列中有任務,就喚醒執行緒佇列中的執行緒來執行這些任務,這些執行緒就相當於“消費者”。模型如下圖。

這裡寫圖片描述

muduo ThreadPool類圖:
這裡寫圖片描述

(1)任務佇列的實現用到了STL的deque容器
deque容器為一個給定型別的元素進行線性處理,像向量一樣,它能夠快速地隨機訪問任一個元素,並且能夠高效地插入和刪除容器的尾部元素。但它又與vector不同,deque支援高效插入和刪除容器的頭部元素,因此也叫做雙端佇列。

deque常用函式如下:

#include <deque>

void push_front(const T& x);  // 雙端佇列頭部增加一個元素x

void push_back(const T& x);   // 雙端佇列尾部增加一個元素x

void pop_front();             // 刪除雙端佇列中最前一個元素

void pop_back();              // 刪除雙端佇列中最後一個元素

void clear();                 // 清空雙端佇列中最後一個元素

reference at(int pos);        // 返回pos位置元素的引用

reference front();            // 返回手元素的引用

reference back();             // 返回尾元素的引用

bool empty() const;           // 向量是否為空,若為true,則向量中無元素

(2)幾個成員函式的說明

檔名:ThreadPool.cc

// 啟動執行緒池,啟動的執行緒是固定個數的(numThreads)
void ThreadPool::start(int numThreads)
{
  assert(threads_.empty()); // 斷言執行緒池是空的
  running_ = true; // 執行狀態標記置為true
  threads_.reserve(numThreads); // 為執行緒池預留指定大小的空間
  // 建立執行緒
  for (int i = 0; i < numThreads; ++i)
  {
    char id[32];
    snprintf(id, sizeof id, "%d", i);
    threads_.push_back(new muduo::Thread(
          boost::bind(&ThreadPool::runInThread, this), name_+id));
    threads_[i].start();
  }
}
檔名:ThreadPool.cc

// 關閉執行緒池
void ThreadPool::stop()
{
  {
  MutexLockGuard lock(mutex_);
  running_ = false; // 執行狀態標識置為false
  cond_.notifyAll(); // 通知所有執行緒
  }
  // 等待所有執行緒關閉
  // boost::bind呼叫類成員函式時需要傳入類成員函式指標、類物件指標...
  for_each(threads_.begin(),
           threads_.end(),
           boost::bind(&muduo::Thread::join, _1));
}
檔名:ThreadPool.cc

// 執行任務  
void ThreadPool::run(const Task& task)  
{  
  // 如果執行緒池沒有執行緒,那麼直接執行任務
  // 也就是說假設沒有消費者,那麼生產者直接消費產品,而不把任務加入任務佇列
  if (threads_.empty())  
  {  
    task();  
  }  
  // 如果執行緒池有執行緒,則將任務新增到任務佇列  
  else  
  {  
    MutexLockGuard lock(mutex_);   
    queue_.push_back(task);  
    cond_.notify();  
  }  
}  
檔名:ThreadPool.cc

// 任務分配函式(獲取任務)
// 執行緒池函式或者執行緒池裡面的函式都可以到這裡取出一個任務
// 然後在自己的執行緒中執行任務,返回一個任務指標  
ThreadPool::Task ThreadPool::take()  
{  
  MutexLockGuard lock(mutex_);  
  // always use a while-loop, due to spurious wakeup(虛假喚醒)
  // 任務佇列為空且執行緒池處於執行狀態,需要等待任務的到來
  while (queue_.empty() && running_)  
  {  
    cond_.wait();  
  }  
  Task task;  
  if(!queue_.empty())  
  {  
    // 獲取任務並彈出
    task = queue_.front();  
    queue_.pop_front();  
  }  
  return task;  
} 

相關推薦

muduo網路學習筆記(5)執行實現

瞭解生產者-消費者問題 生產者-消費者問題也被稱為有界緩衝區問題,兩個程序/執行緒共享一個公共的固定大小的緩衝區。其中一個是生產者,將資訊放入緩衝區;另一個是消費者,從緩衝區中取出資訊。 問題在於當緩衝區已滿,而此時生產者還想向其中放入一個新的資料項的情況。

muduo網路學習筆記(8)高效日誌類的封裝

前言 在服務端程式設計中,日誌是必不可少的。 開發過程中,日誌的存在能方便我們除錯錯誤和更好地理解程式;執行過程中,日誌能幫助我們診斷系統故障並處理、記錄系統執行狀態。 muduo日誌類封裝細

muduo網路學習筆記(14)chargen服務示例

chargen簡介 chargen(Character Generator Protocol)是指在TCP連線建立後,伺服器不斷傳送任意的字元到客戶端,直到客戶端關閉連線。 它生成資料的邏輯如下: for (int i = 33; i < 127;

muduo網路學習筆記(三)TimerQueue定時器佇列

目錄 muduo網路庫學習筆記(三)TimerQueue定時器佇列 Linux中的時間函式 timerfd簡單使用介紹 timerfd示例 muduo中對timerfd的封裝 TimerQueue的結構.

muduo網路學習筆記(四) 通過eventfd實現的事件通知機制

目錄 muduo網路庫學習筆記(四) 通過eventfd實現的事件通知機制 eventfd的使用 eventfd系統函式 使用示例 EventLoop對eventfd的封裝 工作時序 runInLoo

muduo網路學習筆記(五) 連結器Connector與監聽器Acceptor

本篇繼續為前面封裝的EventLoop新增事件,到現在共給EventLoop添加了兩個fd,Timerfd,EventFd分別用於處理定時任務和通知事件. 今天新增的Acceptor會增加另一個fd,此fd是是一個socket,用於監聽套接字連線.同時封裝非組賽網路程式設計中的connect(2)的

C++11併發學習之六執行實現

為什麼要使用執行緒池?       目前的大多數網路伺服器,包括Web伺服器、Email伺服器以及資料庫伺服器等都具有一個共同點,就是單位時間內必須處理數目巨大的連線請求,但處理時間卻相對較短。       傳統多執行緒方案中我們採用的伺服器模型則是一旦接受到請求之後,即建立

Java併發(二十一)執行實現原理 Java併發(十八)阻塞佇列BlockingQueue Java併發(十八)阻塞佇列BlockingQueue Java併發程式設計執行的使用

一、總覽 執行緒池類ThreadPoolExecutor的相關類需要先了解:  (圖片來自:https://javadoop.com/post/java-thread-pool#%E6%80%BB%E8%A7%88) Executor:位於最頂層,只有一個 execute(Runnab

Java併發執行實現原理

一、總覽 執行緒池類ThreadPoolExecutor的相關類需要先了解: Executor:位於最頂層,只有一個 execute(Runnable runnable) 方法,用於提交任務。 ExecutorService :在 Executor 介面的基礎上添加了很多的介面方法,提交任務

Java併發(二十一)執行實現原理

Java併發(二十一):執行緒池實現原理 一、總覽 執行緒池類ThreadPoolExecutor的相關類需要先了解:  (圖片來自:https://javadoop.com/post/java-thread-pool#%E6%80%BB%E8%A7%88) E

muduo網路學習之EventLoop(二)程序(執行)wait/notify 和 EventLoop::runInLoop

// 事件迴圈,該函式不能跨執行緒呼叫 // 只能在建立該物件的執行緒中呼叫void EventLoop::loop() {// 斷言當前處於建立該物件的執行緒中  assertInLoopThread();     while (!quit_)     {         pollReturnTime_ =

Deep Learning 學習筆記5神經網路彙總

本篇文章整理自FJODOR VAN VEEN的論文:The Neural Network Zoo。本文介紹了神經網路大家族,但不是所有的神經網路都能涵蓋,畢竟新的網路結構在不斷被髮展出來。以下是神經網路的圖譜。 介紹神經網路之前,先介紹神經元的分類,這部分內容來自博友的

muduo網路原始碼學習————執行實現

muduo庫裡面的執行緒池是固定執行緒池,即建立的執行緒池裡面的執行緒個數是一定的,不是動態的。執行緒池裡面一般要包含執行緒佇列還有任務佇列,外部程式將任務存放到執行緒池的任務佇列中,執行緒池中的執行緒佇列執行任務,也是一種生產者和消費者模型。muduo庫中的執

hibernate框架學習筆記5緩存

很好 close nts oid img 關閉資源 次方 兩個 res 緩存不止存在與程序中,電腦硬件乃至於生活中都存在緩存 目的:提高效率 比如IO流讀寫字節,如果沒有緩存,讀一字節寫一字節,效率低下 hibernate中的一級緩存:提高操作數據庫的效率 示例:

struts2框架學習筆記5OGNL表達式

closed 在一起 放置 nbsp lap src list 對象 pan OGNL取值範圍分兩部分,root、Context兩部分 可以放置任何對象作為ROOT,CONTEXT中必須是Map鍵值對 示例: 準備工作: public void fun1() th

Kali學習筆記5TCPDUMP詳細使用方法

CA 自己 ring int 十六 一行 全部 kali info Kali自帶Wireshark,但一般的Linux系統是不帶的,需要自行下載,並且過程略復雜 而純字符界面的Linux系統無法使用Wireshark 但是,所有Linux系統都會安裝TCPDUMP:一種基於

Dubbo學習筆記5Dubbo整體框架分析

什麽 資源 AD 文本文件 font ren factor exporter 服務提供者 Dubbo的分層架構 本文將簡單介紹Dubbo的分層架構設計,如下圖是Dubbo官方的整體架構圖: Dubbo官方提供的該架構圖很復雜,一開始我們沒必要深入細節,下面我們簡單介紹

Less學習筆記5匹配模式

匹配模式:類似於JS中的if語句,但不完全是,滿足一定條件後才能匹配 比如:用CSS去畫一個三角 <div class='triangle'></div> .triangle{     width: 0;    &

Deepin學習筆記---如何多執行下載網路檔案

**** 命令列下載網路檔案* 當時看到師兄用多執行緒下載一個檔案,簡直帥呆了,然後自己偷摸學習了一下,很爽,這邊推薦兩個命令列下載網路檔案的方法,前提是要有下載連結哦! 一、 1.wget下載方式 wget http://www.linuxsense.or

視覺化學習筆記5形狀,大小和其他工具

表示資料的其他方式 現在你應該能夠在視覺化圖表中熟練地使用顏色來表示值了。有時候,除了顏色之外,你需要顯示更多的資料。你可以使用不同的表示方式,例如在散點圖中使用不同形狀和大小的標記。下面我將介紹如何使用這些工具在一個圖表中展示更多的資料。