C++线程安全的队列你了解嘛

C++线程安全的队列

什么是线程安全的队列?

线程安全的队列是可以在多个线程同时读写时保证数据一致性和正确性的队列。在多个线程同时对同一个队列进行读写操作时,若不进行同步控制,就会出现数据异常和不一致的情况。线程安全的队列就是为了解决这个问题而设计的一种数据结构。

如何设计线程安全的队列?

设计线程安全的队列主要需要解决以下两个问题:

  1. 如何对队列进行同步控制:对队列的读写操作必须进行同步控制,保证线程之间的数据一致性和正确性。
  2. 如何实现队列的性能优化:一个高效的队列需要具备一定的性能优化,比如延迟申请内存、预申请内存空间等。

一般而言,可以使用互斥锁或者自旋锁来对队列进行同步控制。具体实现细节可参考以下示例代码:

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <chrono>

template<typename T>
class SafeQueue
{
private:
    std::queue<T> _queue;               // 队列
    std::mutex _mutex;                  // 互斥锁

public:
    bool empty() { std::lock_guard<std::mutex> lock(_mutex); return _queue.empty(); }         // 判断队列是否为空
    int size() { std::lock_guard<std::mutex> lock(_mutex); return _queue.size(); }            // 获取队列的大小
    void push(T value) { std::lock_guard<std::mutex> lock(_mutex); _queue.push(value); }      // 将元素入队列
    T pop() { std::lock_guard<std::mutex> lock(_mutex); T value = _queue.front(); _queue.pop(); return value; }                 // 将元素出队列
};

// 测试
int main()
{
    SafeQueue<int> q;

    // 生产者
    std::thread producer([&]() {
        for (int i = 1; i <= 10; i++) {
            q.push(i);
            std::this_thread::sleep_for(std::chrono::milliseconds(10));  // 休眠10毫秒
        }
    });

    // 消费者
    std::thread consumer([&]() {
        while (true) {
            if (q.empty()) continue;

            int value = q.pop();
            std::cout << "消费者消费: " << value << std::endl;

            if (value == 10) break;         // 生产者线程结束循环后,退出消费者线程
        }
    });

    producer.join();
    consumer.join();

    return 0;
}

线程安全的队列的应用示例

应用示例1:多线程文件IO操作

多线程支持高效的文件IO操作是一个非常常见的应用场景,通常在一个线程中读取文件数据,然后将读取到的数据写入到线程安全的队列中,之后再在另外的线程中从队列中取出数据进行处理。以下是一个简单的多线程文件IO操作示例:

#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <condition_variable>

template<typename T>
class SafeQueue
{
private:
    std::queue<T> _queue;                                   // 队列
    mutable std::mutex _mutex;                              // 互斥锁
    std::condition_variable _cond;                          // 条件变量

public:
    bool empty() const { std::lock_guard<std::mutex> lock(_mutex); return _queue.empty(); }         // 判断队列是否为空
    int size() const { std::lock_guard<std::mutex> lock(_mutex); return _queue.size(); }            // 获取队列的大小
    void push(T value) { std::lock_guard<std::mutex> lock(_mutex); _queue.push(value); _cond.notify_all(); }      // 将元素入队列
    T pop() { std::unique_lock<std::mutex> lock(_mutex); _cond.wait(lock, [=] { return !_queue.empty(); }); T value = _queue.front(); _queue.pop(); return value; }           // 将元素出队列并等待队列非空通知
};

void readFile(std::ifstream& ifs, SafeQueue<std::string>& q)
{
    std::string line;

    while (std::getline(ifs, line)) {
        q.push(line);
    }
}

void writeFile(std::ofstream& ofs, SafeQueue<std::string>& q)
{
    while (true) {
        if (q.empty()) continue;

        std::string line = q.pop();
        ofs << line << std::endl;

        if (line == "exit") break;
    }
}

int main()
{
    std::ifstream ifs("input.txt");
    std::ofstream ofs("output.txt");

    SafeQueue<std::string> q;

    // 读取文件
    std::thread reader([&]() { readFile(ifs, q); });

    // 写入文件
    std::thread writer([&]() { writeFile(ofs, q); });

    reader.join();
    writer.join();

    return 0;
}

应用示例2:多线程爬虫

多线程爬虫是另一个常见的应用场景,可以使用线程安全的队列来存储待爬取的URL,然后多个爬虫线程从队列中取出URL进行解析和爬取。以下是一个简单的多线程爬虫示例:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <curl/curl.h>

template<typename T>
class SafeQueue
{
private:
    std::queue<T> _queue;                                   // 队列
    mutable std::mutex _mutex;                              // 互斥锁
    std::condition_variable _cond;                          // 条件变量

public:
    bool empty() const { std::lock_guard<std::mutex> lock(_mutex); return _queue.empty(); }         // 判断队列是否为空
    int size() const { std::lock_guard<std::mutex> lock(_mutex); return _queue.size(); }            // 获取队列的大小
    void push(T value) { std::lock_guard<std::mutex> lock(_mutex); _queue.push(value); _cond.notify_all(); }      // 将元素入队列
    T pop() { std::unique_lock<std::mutex> lock(_mutex); _cond.wait(lock, [=] { return !_queue.empty(); }); T value = _queue.front(); _queue.pop(); return value; }           // 将元素出队列并等待队列非空通知
};

size_t writeFunction(void* ptr, size_t size, size_t nmemb, std::string* data)
{
    data->append((char*)ptr, size * nmemb);

    return size * nmemb;
}

void worker(SafeQueue<std::string>& q)
{
    CURL* curl = curl_easy_init();
    std::string url;

    while (true) {
        if (q.empty()) continue;

        url = q.pop();

        if (url == "exit") break;

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

        std::string response;
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

        CURLcode res = curl_easy_perform(curl);

        if (res == CURLE_OK) {
            std::cout << url << ": " << response.size() << std::endl;
        } else {
            std::cerr << "HTTP error code: " << res << std::endl;
        }
    }

    curl_easy_cleanup(curl);
}

int main()
{
    SafeQueue<std::string> q;
    std::vector<std::thread> threads;

    threads.push_back(std::thread([&]() { worker(q); }));
    threads.push_back(std::thread([&]() { worker(q); }));
    threads.push_back(std::thread([&]() { worker(q); }));

    q.push("https://www.google.com/");
    q.push("https://www.baidu.com/");
    q.push("https://www.bing.com/");
    q.push("exit");

    for (auto& thread : threads) {
        thread.join();
    }

    return 0;
}

以上是线程安全队列的基本知识点和应用实例,希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++线程安全的队列你了解嘛 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C++实现拼图游戏代码(graphics图形库)

    下面我将详细讲解C++实现拼图游戏代码(使用graphics图形库)的攻略。 准备工作 在实现拼图游戏代码之前,我们需要进行一些准备工作。 首先,我们需要下载安装Turbo C++ IDE(或其他C++ IDE),并且需要安装BGI图形库(Borland Graphics Interface)。BGI是一个可以在Turbo C++下使用的图形库,它提供了各种…

    C 2023年5月23日
    00
  • Qt读取Json文件的方法详解(含源码+注释)

    我来给您讲解 “Qt读取Json文件的方法详解(含源码+注释)” 的完整攻略。 标题 标题一 文章开头的第一级标题,可以用 #表示,一般建议使用1~3级标题。 标题二 接下来的内容属于第二级标题,同样用 ## 表示。 正文 文章的正文分为以下几个部分: 1. 引言 引言部分对于文章的整体质量有着举足轻重的影响。我们在介绍Qt读取Json文件的方法时,可以简单…

    C 2023年5月23日
    00
  • C语言实现2D赛车游戏的示例代码

    下面我将详细讲解如何实现一个简单的2D赛车游戏。 1. 实现思路 首先,我们需要了解游戏的基本组成部分: 游戏场景 赛车模型 道路模型 背景音乐 操作控制 根据以上组成部分,我们可以总体将实现思路分为以下几个步骤: 创建画布:使用某种绘图库创建基础画布,用于绘制游戏场景。 绘制游戏场景:在基础画布上绘制游戏所需的场景元素,包括道路和赛车模型。 添加背景音乐:…

    C 2023年5月23日
    00
  • Win11系统遇到BSOD错误代码0xc0000001怎么办 附图文修复教程

    当 Win11 系统遇到 BSOD 错误代码 0xc0000001 的时候,这意味着操作系统自举的过程中发生了错误。这种错误可能是由于硬件故障、软件冲突、缺失关键系统文件等多种原因引起的。 下面是对此问题的解决攻略: 步骤一:检查硬件连接 首先,确保 Win11 计算机的每个硬件部件都正确连接。此外,请确保所有硬件部件都处于工作状态并适当地供电。如果其中某一…

    C 2023年5月23日
    00
  • CGLD是什么币种?一文了解CGLD币怎么样

    CGLD是什么币种? CGLD(Celo Gold)是Celo协议的代币,是以太坊 ERC20 标准代币,也是Celo生态系统中的原生资产。Celo是基于信任的区块链平台,专门设计用于支持金融包容,旨在实现金融服务的覆盖面和可用性。 Celo协议旨在为人们提供使用区块链技术进行支付和汇款服务,特别是为那些没有银行账户的人提供服务。基于Celo 协议的平台允许…

    C 2023年5月23日
    00
  • win7启动程序时弹出异常代码c0000005怎么办?

    下面是“win7启动程序时弹出异常代码c0000005”的完整攻略: 问题描述 在启动某些程序时,可能会遇到异常代码c0000005的错误提示,例如: 异常代码c0000005,详细信息是:ACCESS_VIOLATION 解决方案 方案一:更新或重装程序 可能是程序本身存在问题,建议先到官网下载最新版本安装或者尝试重装程序,看看能否解决问题。 方案二:检查…

    C 2023年5月23日
    00
  • x86汇编DOS编程环境搭建过程

    搭建x86汇编DOS编程环境 1.安装DOSBox DOSBox是一个模拟DOS环境的开源软件,可以在现代操作系统上运行DOS程序。我们可以利用其模拟DOS环境来进行汇编语言程序的编写和调试。 在DOSBox官网上下载适用于你所使用操作系统的DOSBox并安装。 2.下载并安装x86汇编编译器 这里将介绍NASM。 下载NASM:http://www.nas…

    C 2023年5月23日
    00
  • C 标准库 float.h

    C 标准库的 float.h 头文件包含了浮点型数值的一些有用的常量和宏定义。这些常量和宏定义可以帮助我们在程序中进行更精确的浮点数计算。 下面是一些 float.h 头文件中常用的常量和宏定义: 常量 FLT_RADIX:浮点数基数,即底数的数值。 FLT_MANT_DIG:最大二进制位数,通常是23。 DBL_MANT_DIG:一个 double 类型变…

    C 2023年5月10日
    00
合作推广
合作推广
分享本页
返回顶部