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日

相关文章

  • java调用外部程序的方法及代码演示

    Java调用外部程序是一种常见场景,我们可以使用Java语言来方便地与外部程序进行交互。在本篇文章中,我将为大家详细讲解Java调用外部程序的方法及代码演示。 一、使用Runtime类调用外部程序 1.1 Runtime.getRuntime().exec()方法 Java提供了Runtime类来处理与系统进程的交互,我们可以使用该类的exec()方法来启动…

    C 2023年5月23日
    00
  • C++实现评教管理系统

    下面我将详细讲解C++ 实现评教管理系统的完整攻略。 1. 确定需求 在开始编写代码之前,我们需要明确需求。在该项目中,我们需要实现一个评教管理系统,包含学生登录、教师登录、评教功能等。 2. 设计数据库 在设计数据库时,我们需要确定数据库的表结构和字段,其中包括学生表、教师表和评教表。例如: 学生表: 字段 数据类型 描述 id int 学号 name v…

    C 2023年5月30日
    00
  • JSON数据中存在单个转义字符“\”的处理方法

    处理 JSON 数据中存在单个转义字符“\”的方法有以下两种: 双反斜线转义为单斜线 当 JSON 数据中存在单个反斜线时,可以使用双反斜线转义为单斜线处理。示例如下: { "text": "这是一句包含反斜线\\的文本" } 可以通过代码将其转化为: { "text": "这是一句包含反…

    C 2023年5月23日
    00
  • Python JSON模块的使用详情

    Python JSON模块的使用详情 什么是JSON? JSON是JavaScript对象表示法(JavaScript Object Notation)的缩写,是一种轻量级的数据交换格式。它以易于阅读和编写的文本格式为基础,通常用于在网络之间传输数据。在Python中,有一个常用的模块叫做json,可以方便地对JSON数据进行编码和解码操作。 序列化与反序列…

    C 2023年5月23日
    00
  • 浅析C++内存布局

    浅析C++内存布局 C++是一门面向过程的编程语言,与其他编程语言一样,C++也有自己的内存布局。 内存布局基本概念 堆 使用new或malloc操作后存放动态分配的数据的区域。 栈 用于存放程序运行时的函数栈帧,栈帧将在函数执行完后自行清除。 全局变量区 在程序运行前就分配好的存放全局变量的区域,该区域分为静态区和可读写区。 常量区 存放程序中常量的区域,…

    C 2023年5月22日
    00
  • C++代码和可执行程序在x86和arm上的区别介绍

    下面是C++代码和可执行程序在x86和ARM上的区别介绍的攻略。 x86和ARM的区别 x86和ARM是两种不同的指令集架构。x86是发达国家使用最多的CPU架构之一,而ARM则是集成电路行业中应用广泛的CPU架构之一。 在x86架构中,CPU使用的指令集是复杂指令集指令集(CISC)。这意味着,CPU可以执行很复杂的操作,比如浮点数运算。C++代码在x86…

    C 2023年5月23日
    00
  • golang常用加密解密算法总结(AES、DES、RSA、Sha1、MD5)

    Golang常用加密解密算法总结 Golang提供了丰富的加密解密算法库,本篇文章将介绍常用的加密解密算法:AES、DES、RSA、Sha1、MD5。 AES(Advanced Encryption Standard) AES加密算法是目前应用最广泛的对称加密算法,在网络传输中常作为对称加密方式使用。AES算法支持多种不同的密钥长度,包括128位,192位和…

    C 2023年5月23日
    00
  • Maplesoft Maple 2020官方正式版安装教程图文详细介绍(含下载地址)

    Maplesoft Maple 2020正式版安装教程 本文介绍了Maplesoft Maple 2020正式版的安装方法,包括下载和安装过程。 下载Maple软件 官网下载链接:https://www.maplesoft.com/support/downloads/ 访问上述链接,找到Maple软件的下载链接,选择合适的版本下载。 下载完成后双击安装包,开…

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