欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++基于消息隊列的多線程實現(xiàn)示例代碼

 更新時間:2019年04月05日 10:17:16   作者:Leon_30f5  
這篇文章主要給大家介紹了關于C++基于消息隊列的多線程實現(xiàn)的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用C++具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

前言

實現(xiàn)消息隊列的關鍵因素是考量不同線程訪問消息隊列的同步問題。本實現(xiàn)涉及到幾個知識點

std::lock_guard 介紹

std::lock_gurad 是 C++11 中定義的模板類。定義如下:

template <class Mutex> class lock_guard;

lock_guard 對象通常用于管理某個鎖(Lock)對象,因此與 Mutex RAII 相關,方便線程對互斥量上鎖,即在某個 lock_guard 對象的聲明周期內,它所管理的鎖對象會一直保持上鎖狀態(tài);而 lock_guard 的生命周期結束之后,它所管理的鎖對象會被解鎖(注:類似 shared_ptr 等智能指針管理動態(tài)分配的內存資源 )。

模板參數(shù) Mutex 代表互斥量類型,例如 std::mutex 類型,它應該是一個基本的 BasicLockable 類型,標準庫中定義幾種基本的 BasicLockable 類型,分別 std::mutex, std::recursive_mutex, std::timed_mutex,std::recursive_timed_mutex 以及 std::unique_lock

std::unique_lock 介紹

lock_guard 最大的缺點也是簡單,沒有給程序員提供足夠的靈活度,因此,C++11 標準中定義了另外一個與 Mutex RAII 相關類 unique_lock,該類與 lock_guard 類相似,也很方便線程對互斥量上鎖,但它提供了更好的上鎖和解鎖控制。
顧名思義,unique_lock 對象以獨占所有權的方式( unique owership)管理 mutex 對象的上鎖和解鎖操作,所謂獨占所有權,就是沒有其他的 unique_lock 對象同時擁有某個 mutex 對象的所有權。

新創(chuàng)建的 unique_lock 對象管理 Mutex 對象 m,并嘗試調用 m.lock() 對 Mutex 對象進行上鎖,如果此時另外某個 unique_lock 對象已經管理了該 Mutex 對象 m,則當前線程將會被阻塞。

std::condition介紹

當 std::condition_variable 對象的某個 wait 函數(shù)被調用的時候,它使用 std::unique_lock(通過 std::mutex) 來鎖住當前線程。當前線程會一直被阻塞,直到另外一個線程在相同的 std::condition_variable 對象上調用了 notification 函數(shù)來喚醒當前線程。

std::condition_variable 提供了兩種 wait() 函數(shù)。當前線程調用 wait() 后將被阻塞(此時當前線程應該獲得了鎖(mutex),不妨設獲得鎖 lck),直到另外某個線程調用 notify_* 喚醒了當前線程。

在線程被阻塞時,該函數(shù)會自動調用 lck.unlock() 釋放鎖,使得其他被阻塞在鎖競爭上的線程得以繼續(xù)執(zhí)行。另外,一旦當前線程獲得通知(notified,通常是另外某個線程調用 notify_* 喚醒了當前線程),wait() 函數(shù)也是自動調用 lck.lock(),使得 lck 的狀態(tài)和 wait 函數(shù)被調用時相同。

在第二種情況下(即設置了 Predicate),只有當 pred 條件為 false 時調用 wait() 才會阻塞當前線程,并且在收到其他線程的通知后只有當 pred 為 true 時才會被解除阻塞。因此第二種情況類似以下代碼:

while (!pred()) wait(lck);

std::function介紹

使用std::function可以將普通函數(shù),lambda表達式和函數(shù)對象類統(tǒng)一起來。它們并不是相同的類型,然而通過function模板類,可以轉化為相同類型的對象(function對象),從而放入一個vector或其他容器里,方便回調。

代碼實現(xiàn):

#pragma once

#ifndef MESSAGE_QUEUE_H
#define MESSAGE_QUEUE_H

#include <queue>
#include <mutex>
#include <condition_variable>

template<class Type>
class CMessageQueue
{
public:
 CMessageQueue& operator = (const CMessageQueue&) = delete;
 CMessageQueue(const CMessageQueue& mq) = delete;


 CMessageQueue() :_queue(), _mutex(), _condition(){}
 virtual ~CMessageQueue(){}

 void Push(Type msg){
  std::lock_guard <std::mutex> lock(_mutex);
  _queue.push(msg);
   //當使用阻塞模式從消息隊列中獲取消息時,由condition在新消息到達時提醒等待線程
  _condition.notify_one();
 }
  //blocked定義訪問方式是同步阻塞或者非阻塞模式
 bool Pop(Type& msg, bool isBlocked = true){
  if (isBlocked)
  {
   std::unique_lock <std::mutex> lock(_mutex);
   while (_queue.empty())
   {
    _condition.wait(lock);
    
   }
   //注意這一段必須放在if語句中,因為lock的生命域僅僅在if大括號內
   msg = std::move(_queue.front());
   _queue.pop();
   return true;
   
  }
  else
  {
   std::lock_guard<std::mutex> lock(_mutex);
   if (_queue.empty())
    return false;


   msg = std::move(_queue.front());
   _queue.pop();
   return true;
  }

 }

 int32_t Size(){
  std::lock_guard<std::mutex> lock(_mutex);
  return _queue.size();
 }

 bool Empty(){
  std::lock_guard<std::mutex> lock(_mutex);
  return _queue.empty();
 }
private:
 std::queue<Type> _queue;//存儲消息的隊列
 mutable std::mutex _mutex;//同步鎖
 std::condition_variable _condition;//實現(xiàn)同步式獲取消息
};

#endif//MESSAGE_QUEUE_H

線程池可以直接在構造函數(shù)中構造線程,并傳入回調函數(shù),也可以寫一個Run函數(shù)顯示調用。這里我們選擇了第二種,對比:

  1. 在handler函數(shù)外部做循環(huán)接受消息,當消息到達后調用hanlder處理。這種實現(xiàn)在上層做封裝,但是會在線程中頻繁的切換調用函數(shù)。這種設計無法復用一些資源,如當在handler中做數(shù)據(jù)庫操作時,需要頻繁的連接和斷開連接,可以通過定義兩個虛函數(shù)Prehandler和AfterHandler來實現(xiàn)。
    ?。?!構造函數(shù)中調用虛函數(shù)并不會能真正的調用子類的實現(xiàn)?。?!
    雖然可以對虛函數(shù)進行實調用,但程序員編寫虛函數(shù)的本意應該是實現(xiàn)動態(tài)聯(lián)編。在構造函數(shù)中調用虛函數(shù),函數(shù)的入口地址是在編譯時靜態(tài)確定的,并未實現(xiàn)虛調用
  2. 寫一個Run函數(shù),將這一部分實現(xiàn)放在run函數(shù)中,顯示調用。
    《Effective C++ 》條款9:永遠不要在構造函數(shù)或析構函數(shù)中調用虛函數(shù)
#ifndef THREAD_POOL_H
#define THREAD_POOL_H


#include <functional>
#include <vector>
#include <thread>

#include "MessageQueue.h"

#define MIN_THREADS 1

template<class Type>
class CThreadPool
{
 CThreadPool& operator = (const CThreadPool&) = delete;
 CThreadPool(const CThreadPool& other) = delete;

public:
 CThreadPool(int32_t threads, 
  std::function<void(Type& record, CThreadPool<Type>* pSub)> handler);
 virtual ~CThreadPool();

 void Run();
 virtual void PreHandler(){}
 virtual void AfterHandler(){}
 void Submit(Type record);


private:
 bool _shutdown;
 int32_t _threads;
 std::function<void(Type& record, CThreadPool<Type>* pSub)> _handler;
 std::vector<std::thread> _workers;
 CMessageQueue<Type> _tasks;

};



template<class Type>
CThreadPool<Type>::CThreadPool(int32_t threads, 
 std::function<void(Type& record, CThreadPool<Type>* pSub)> handler)
 :_shutdown(false),
 _threads(threads),
 _handler(handler),
 _workers(),
 _tasks()
{

 //第一種實現(xiàn)方案,注意這里的虛函數(shù)調用不正確
 /*if (_threads < MIN_THREADS)
  _threads = MIN_THREADS;
 for (int32_t i = 0; i < _threads; i++)
 {
  
  _workers.emplace_back(
   [this]{
   PreHandler();
   while (!_shutdown){
    Type record;
    _tasks.Pop(record, true);
    _handler(record, this);
   }
   AfterHandler();
  }
  );
 }*/

}

//第二種實現(xiàn)方案
template<class Type>
void CThreadPool<Type>::Run()
{
 if (_threads < MIN_THREADS)
  _threads = MIN_THREADS;
 for (int32_t i = 0; i < _threads; i++)
 {
  _workers.emplace_back(
   [this]{
   PreHandler();
   while (!_shutdown){
    Type record;
    _tasks.Pop(record, true);
    _handler(record, this);
   }
   AfterHandler();
  }
  );
 }
}




template<class Type>
CThreadPool<Type>::~CThreadPool()
{
 for (std::thread& worker : _workers)
  worker.join();
}


template<class Type>
void CThreadPool<Type>::Submit(Type record)
{
 _tasks.Push(record);
}
#endif // !THREAD_POOL_H

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

相關文章

  • c語言求出給定范圍內的所有質數(shù)

    c語言求出給定范圍內的所有質數(shù)

    本文主要介紹了c語言求出給定范圍內的所有質數(shù)的小程序。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-04-04
  • C++類與對象的詳細說明

    C++類與對象的詳細說明

    這篇文章主要為大家詳細介紹了C++的類與對象,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • vs2019配置C++版OpenCV的方法步驟

    vs2019配置C++版OpenCV的方法步驟

    最近要用到很多OpenCV的庫,所以開始學了點OpenCV,本文記錄VS和OpenCV的安裝、配置過程。具有一定的參考價值,感興趣的可以了解一下
    2021-09-09
  • C語言利用EasyX繪制小企鵝表情包

    C語言利用EasyX繪制小企鵝表情包

    這篇文章主要為大家詳細介紹了C語言如何利用EasyX繪圖庫實現(xiàn)繪制可愛的小企鵝表情包,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2022-12-12
  • opencv幀差法找出相差大的圖像

    opencv幀差法找出相差大的圖像

    這篇文章主要為大家詳細介紹了opencv幀差法找出相差大的圖像,包含訪問mat的像素值,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • 推薦幾款C/C++的編譯器、編譯環(huán)境(非常全面的比較)

    推薦幾款C/C++的編譯器、編譯環(huán)境(非常全面的比較)

    這篇文章主要介紹了C/C++編譯器的一些易混淆概念,這里腳本之家小編特為大家分享一下,需要的朋友可以參考下
    2021-06-06
  • C++實現(xiàn)并優(yōu)化異常系統(tǒng)

    C++實現(xiàn)并優(yōu)化異常系統(tǒng)

    異常處理是C++的一項語言機制,用于在程序中處理異常事件,下面這篇文章主要給大家介紹了關于C++中異常的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • C語言小游戲之簡易版三子棋(棋盤可自由擴展)

    C語言小游戲之簡易版三子棋(棋盤可自由擴展)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)三子棋游戲,還可以自由擴展棋盤大小,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C++的運算符你真的了解嗎

    C++的運算符你真的了解嗎

    這篇文章主要為大家詳細介紹了C++的運算符,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • C++?Primer學習記錄之變量

    C++?Primer學習記錄之變量

    這篇文章主要為大家介紹了C++Primer之變量,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01

最新評論