实现线程安全的队列

news/2024/10/31 1:23:20/

假设我们忽略构造、赋值、互换、拷贝,那么只剩下3组操作。

1:empty、size,用于查询队列的整体状态

2:front、back,用于查询队列中的元素

3:push、pop,用于修改队列

一些细节:

  • 由于接口存在固有的条件竞争,所以需要把front和pop合并成一个函数,这个和栈容器的top、pop合并非常类似。
  • 当队列用于线程间传递数据的时候,负责接收的线程通常需要等待线程压入。所以需要提供两个pop变体:
    • try_pop:试图弹出队首元素,若失败直接返回
    • wait_and_pop:试图弹出队首元素,若失败,等待到有数据可以读
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>#include <memory>
template<typename T>class threadsafe_queue {
private:mutable std::mutex mtx;     // 互斥必须用mutable修饰(针对const对象,准许其数据成员发生变动)std::queue<T> data_queue;std::condition_variable data_cond;
public:threadsafe_queue() {}threadsafe_queue(threadsafe_queue const& other) {std::lock_guard<std::mutex> lk(other.mtx);data_queue = other.data_queue;}threadsafe_queue(threadsafe_queue&& other) {std::lock_guard<std::mutex> lk(other.mtx);data_queue = std::move(other.data_queue);}threadsafe_queue& operator=(threadsafe_queue const& other) {std::lock_guard<std::mutex> lk(mtx);data_queue = other.data_queue;return *this;}threadsafe_queue& operator=(threadsafe_queue&& other) {std::lock_guard<std::mutex> lk(mtx);data_queue = std::move(other.data_queue);return *this;}void push(T new_value) {std::lock_guard<std::mutex> lk(mtx);data_queue.push(new_value);data_cond.notify_one();}void wait_and_pop(T& value) {std::unique_lock<std::mutex> lk(mtx);data_cond.wait(lk,[this]{return !data_queue.empty();});value = data_queue.front();data_queue.pop();}std::shared_ptr<T> wait_and_pop() {std::unique_lock<std::mutex> lk(mtx);data_cond.wait(lk, [this] {return !data_queue.empty();});std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));data_queue.pop();return res;}bool try_pop(T& value) {std::lock_guard<std::mutex> lk(mtx);if (data_queue.empty()) {return false;}value = data_queue.front();data_queue.pop();return true;}std::shared_ptr<T> try_pop() {std::lock_guard<std::mutex> lk(mtx);if (data_queue.empty()) {return std::shared_ptr<T>();}std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));data_queue.pop();return res;}bool empty() const {std::lock_guard<std::mutex> lk(mtx);return data_queue.empty();}size_t size() const {std::lock_guard<std::mutex> lk(mtx);return data_queue.size();}
};void producer(threadsafe_queue<int>& q) {for (int i = 0; i < 10; ++i) {q.push(i);std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}void consumer(threadsafe_queue<int>& q) {int value;for (int i = 0; i < 10; ++i) {q.wait_and_pop(value);std::cout << "Consumer got value: " << value << std::endl;}
}int main() {threadsafe_queue<int> q;std::thread t1(producer, std::ref(q));std::thread t2(consumer, std::ref(q));t1.join();t2.join();return 0;
}

在这个示例代码中,我们定义了一个生产者函数 producer 和一个消费者函数 consumer,它们分别向 threadsafe_queue 中推入数据和从中取出数据。我们创建了一个 threadsafe_queue 对象 q,并在两个线程中分别调用 producerconsumer 函数。在 producer 函数中,我们向 q 中推入了 10 个整数,每个整数之间间隔 100 毫秒。在 consumer 函数中,我们从 q 中取出了 10 个整数,并输出了每个整数的值。

需要注意的是,threadsafe_queue 是一个线程安全的队列,它使用了互斥量和条件变量来保证线程安全。在使用 threadsafe_queue 时,需要注意避免死锁和竞争条件的问题。同时,为了避免拷贝和移动对象时出现问题,我们增加了移动构造、析构函数、拷贝赋值运算符、移动赋值运算符。


http://www.ppmy.cn/news/365038.html

相关文章

笔记本切换屏幕到投影仪

转载于这里 要想笔记本上的画面通过投影机进行显示&#xff0c;首先得将笔记本的信号传输到投影机上面&#xff0c;几乎所有笔记本上都有一个专门用于切换投影机的F功能按键&#xff0c;只需要同时按住Fn以及F功能按键就可以切换信号了。 不同品牌笔记本切换到投影机的按键汇总…

投影仪的使用

投影仪的使用方法 1.打开投影柜&#xff0c;轻放柜盖。使投影仪和银幕的距离保持在1.5—2米。在确定所有操作开关处于关闭状态后&#xff0c;接通电源。 2.掰住支撑杆托架&#xff08;卡子&#xff09;&#xff0c;扶着支撑杆推至于投影面垂直&#xff0c;此时会有“卡它”声&…

Linux系统时间介绍和校时

从timedatectl 可以看到有本地时间、UTC时间、RTC时间和时区信息&#xff0c;如下&#xff1a; Local time: Tue 2022-06-13 14:30:31 CST Universal time: Tue 2022-06-13 06:30:31 UTC RTC time: Tue 2022-06-13 06:30:32 Time zone: Asia/Shanghai (CST, 0800) Local time: …

软件测试进阶知识 —— 性能测试

性能测试 性能测试是指在一定条件下系统行为表现是否符合需求规格的性能指标。 例如&#xff0c;通过测试传输的最长时限、传输的错误率、计算的精度、响应的时限和恢复时限等性能指标&#xff0c;验证了软件系统是否能够达到需求规格说明中所提出的性能指标&#xff0c;发现了…

C#Winform文件流FileStream实例讲解

一、FileStream类介绍 FileStream类读取、写入、打开和关闭文件系统上的文件,并操作其他与文件相关的操作系统句柄,包括管道、标准输入和标准输出。 函数及方法 1.1构造函数 FileStream() : public FileStream (string path, System.IO.FileMode mode, System.IO.FileA…

C# 自动备份文件

目录 文件目录如下 APBackUpFiles app.config OracleHelper LocalFileMethods LogFile packages.config ReadFile 如何发布 在工作的时候&#xff0c;遇到了需要定时对服务器的文件进行备份的需求&#xff0c;原因是 AP&#xff08;服务器&#xff09;上的空间不够了&a…

(一)ElasticSearch介绍

1.概述&#xff1a; Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;用于快速、可扩展和实时地搜索、分析和存储大量数据。它是在 Apache Lucene 基础上构建的&#xff0c;Lucene 是一个强大的全文搜索库。 2.特点&#xff1a; Elasticsearch 被设计用于处理各…

AES-128-ECB php兼容高低版本

class Aes {/*** 加密* param $plain* param $key* return false|string*/public static function encrypt($plain, $key){if (trim($key) ) {return false;}$key self::_sha1prng($key);if(version_compare(PHP_VERSION,7.1,>)){$iv ;$encrypted openssl_encrypt($plai…