91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

利用C++實現阻塞隊列的示例

發布時間:2020-10-30 00:16:47 來源:億速云 閱讀:285 作者:Leah 欄目:開發技術

本篇文章為大家展示了利用C++實現阻塞隊列的示例,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

阻塞隊列是多線程中常用的數據結構,對于實現多線程之間的數據交換、同步等有很大作用。

阻塞隊列常用于生產者和消費者的場景,生產者是向隊列里添加元素的線程,消費者是從隊列里取元素的線程。簡而言之,阻塞隊列是生產者用來存放元素、消費者獲取元素的容器。

考慮下,這樣一個多線程模型,程序有一個主線程 master 和一些 worker 線程,master 線程負責接收到數據,給 worker 線程分配數據,worker 線程取得一個任務后便可以開始工作,如果沒有任務便阻塞住,節約 cpu 資源。

  • master 線程  (生產者):負責往阻塞隊列中塞入數據,并喚醒正在阻塞的 worker 線程。
  • workder 線程(消費者):負責從阻塞隊列中取數據,如果沒有數據便阻塞,直到被 master 線程喚醒。

那么怎樣的數據結構比較適合做這樣的喚醒呢?顯而易見,是條件變量,在 c++ 11 中,stl 已經引入了線程支持庫。

C++11 中條件變量

條件變量一般與一個 互斥量 同時使用,使用時需要先給互斥量上鎖,然后條件變量會檢測是否滿足條件,如果不滿足條件便會暫時釋放鎖,然后阻塞線程。

c++ 11使用方法主要如下:

#include <mutex>
#include <condition_value>
// 互斥量與條件變量
std::mutex m_mutex;
std::condition_value m_condition;

// 請求信號的一方
std::unique_lock<std::mutex> lock(mutex);
while(xxx)
{
 // 這里會先釋放 lock,
 // 如果有信號喚醒的話,會重新加鎖。
 m_condition.wait(lock);
}

// 發送消息進行同步的一方
{
 std::unique_lock<std::mutex> lock(mutex);
 // 喚醒其他正在 wait 的線程
 m_condition.notify_all();
}

用 C++11 實現阻塞隊列

我們使用條件變量包裝 STL 中的 queue 就可以實現阻塞隊列功能,如果有興趣,甚至可以自己實現一個效率更高的隊列數據結構。

我們先假設一下阻塞隊列需要如下接口:

  • push 將一個變量塞入隊列;
  • take 從隊列中取出一個元素;
  • size 查看隊列有多少個元素;
template <typename T>
class BlockingQueue
{
public:
 BlockingQueue();
 void push(T&& value);
 T take();
 size_t size() const;
 
private:
 // 實際使用的數據結構隊列
 std::queue<T> m_data;

 // 條件變量
 std::mutex m_mutex;
 std::condition_variable m_condition;
};

push 一個變量時,我們需要先加鎖,加鎖成功后才可以壓入變量,這是為了線程安全。壓入變量后,就可以發送信號通知正在阻塞的條件變量。

 void push(T&& value)
 {
  // 往隊列中塞數據前要先加鎖
  std::unique_lock<std::mutex> lock(m_mutex);
  m_data.push(value);
  // 喚醒正在阻塞的條件變量
  m_condition.notify_all();
 }

take 一個變量時,就要有些不一樣:

  1. 先加鎖,加鎖成功后,如果隊列不為空,可以直接取數據,不需要 wait;
  2. 如果隊列為空呢,則 wait 等待,直到被喚醒;
  3. 考慮特殊情況,喚醒后隊列依然是空的……
 T take()
 {
  std::unique_lock<std::mutex> lock(m_mutex);
  while(m_data.empty())
  {
   // 等待
   m_condition.wait(lock);
  }
  assert(!m_data.empty());
  T value(std::move(m_data.front()));
  m_data.pop();

  return value;
 }

總結下,代碼如下:

#ifndef BLOCKINGQUEUE_H
#define BLOCKINGQUEUE_H

#include <queue>
#include <mutex>
#include <condition_variable>
#include <assert.h>

template <typename T>
class BlockingQueue
{
public:
 BlockingQueue()
  :m_mutex(),
   m_condition(),
   m_data()
 {
 }

 // 禁止拷貝構造
 BlockingQueue(BlockingQueue&) = delete;

 ~BlockingQueue()
 {
 }

 void push(T&& value)
 {
  // 往隊列中塞數據前要先加鎖
  std::unique_lock<std::mutex> lock(m_mutex);
  m_data.push(value);
  m_condition.notify_all();
 }

 void push(const T& value)
 {
  std::unique_lock<std::mutex> lock(m_mutex);
  m_data.push(value);
  m_condition.notify_all();
 }

 T take()
 {
  std::unique_lock<std::mutex> lock(m_mutex);
  while(m_data.empty())
  {
   m_condition.wait(lock);
  }
  assert(!m_data.empty());
  T value(std::move(m_data.front()));
  m_data.pop();

  return value;
 }

 size_t size() const
 {
  std::unique_lock<std::mutex> lock(m_mutex);
  return m_data.size();
 }
private:
 // 實際使用的數據結構隊列
 std::queue<T> m_data;

 // 條件變量的鎖
 std::mutex m_mutex;
 std::condition_variable m_condition;
};
#endif // BLOCKINGQUEUE_H

實驗代碼

我們寫個簡單的程序實驗一下,下面程序有 一個 master 線程,5個 worker 線程,master線程生成一個隨機數,求 0-隨機數 的和。

#include <iostream>
#include <thread>
#include <mutex>
#include <random>

#include <windows.h>

#include <blockingqueue.h>
using namespace std;

int task=100;
BlockingQueue<int> blockingqueue;
std::mutex mutex_cout;

void worker()
{
 int value;
 thread::id this_id = this_thread::get_id();
 while(true)
 {
  value = blockingqueue.take();
  uint64_t sum = 0;
  for(int i = 0; i < value; i++)
  {
   sum += i;
  }

  // 模擬耗時操作
  Sleep(100);

  std::lock_guard<mutex> lock(mutex_cout);
  std::cout << "workder: " << this_id << " "
     << __FUNCTION__
     << " line: " << __LINE__
     << " sum: " << sum
     << std::endl;
 }
}

void master()
{
 srand(time(nullptr));
 for(int i = 0; i < task; i++)
 {
  blockingqueue.push(rand()%10000);
  printf("%s %d %i\n",__FUNCTION__, __LINE__, i);
  Sleep(20);
 }
}

int main()
{
 thread th_master(master);
 std::vector<thread> th_workers;
 for(int i =0; i < 5; i++)
 {
  th_workers.emplace_back(thread(worker));
 }

 th_master.join();
 return 0;
}

從輸出結果可以看出,master 線程將任務分配給了正在空閑的 worker 線程,具體是哪個線程就看操作系統的隨機調度了。

master 46 5
worker: 3 worker line: 34 sum: 20998440
master 46 6
worker: 7 worker line: 34 sum: 3308878
master 46 7
worker: 4 worker line: 34 sum: 34598721
master 46 8
worker: 6 worker line: 34 sum: 1563796
master 46 9
worker: 5 worker line: 34 sum: 27978940

上述內容就是利用C++實現阻塞隊列的示例,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

通化县| 沙雅县| 上林县| 剑河县| 萨嘎县| 金阳县| 大余县| 奉贤区| 交城县| 嘉峪关市| 普格县| 台安县| 汽车| 团风县| 塘沽区| 长泰县| 横山县| 梅河口市| 泸溪县| 乌什县| 绥芬河市| 安仁县| 雷山县| 江安县| 思南县| 蓝山县| 高密市| 湟中县| 溆浦县| 福安市| 历史| 宜宾市| 扬州市| 浮山县| 西贡区| 龙州县| 磴口县| 黔西县| 海城市| 蓬溪县| 本溪|