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日

相关文章

  • 荣耀畅玩7c怎么开启热点?荣耀畅玩7c开启热点教程

    下面给您详细讲解荣耀畅玩7c如何开启热点的完整攻略: 一、前置条件 在进行热点开启之前,请确保您的荣耀畅玩7c已经连接到移动网络,并且您已经知道热点开启会消耗您的移动网络流量。 二、开启热点 从荣耀畅玩7c的系统设置进入到 “更多连接方式” 页面。 在更多连接方式页面中,点击 “个人热点”。如果您没有在荣耀畅玩7c上设置过热点,第一次点击个人热点会提示您开启…

    C 2023年5月23日
    00
  • 华硕X550C怎么拆机 华硕X550C清理灰尘与升级SSD图文教程

    华硕X550C是一款经典的笔记本电脑,通常情况下使用时间长了之后就会出现散热问题或者存储容量不足的问题。为了解决这些问题,我们需要拆卸笔记本电脑并进行清理灰尘或者升级SSD。下面我将为大家提供华硕X550C拆机、清理灰尘以及升级SSD的详细攻略。 步骤一:准备工作 首先,我们需要准备以下材料: 十字螺丝刀 塑料卡片 SSD硬盘 硬盘盒 硅脂 清洁剂 清理刷 …

    C 2023年5月23日
    00
  • 剖析C语言关键字之void,const,return

    剖析C语言关键字之void 概述 void 是 C 语言中表示“无类型”的关键字。它通常用于函数声明,表示该函数不返回任何值。 函数声明 使用 void 关键字的函数声明可以没有参数也可以有一个或多个参数,但是不会返回任何值。例如: void myFunction(void); void myFunctionWithParams(int a, float b…

    C 2023年5月24日
    00
  • Visual Studio Code (vscode) 配置 C / C++ 环境的流程

    Visual Studio Code(以下简称VSCode)是一个强大的代码编辑器,它支持多种编程语言,包括C/C++。本篇攻略将会详细讲解在VSCode中配置C/C++环境的流程。 安装 C / C++插件 首先,你需要在VSCode中安装C/C++插件来加强其与C/C++语言的兼容性。在VSCode的插件市场中搜索”C/C++”,然后点击”安装”完成安装…

    C 2023年5月23日
    00
  • 基于javascript实现按圆形排列DIV元素(二)

    基于JavaScript实现按圆形排列DIV元素的完整攻略如下: 步骤1:构建HTML结构 首先,我们需要构建一个HTML页面,并在其中添加一个父级div元素和一些子级的div元素。父级div元素用于容纳所有子级div元素,并设置其宽度和高度为固定值,例如600px。子级div元素用于显示实际内容,我们只需要设置它们的宽度和高度即可。 <div id=…

    C 2023年5月22日
    00
  • 完全掌握C++编程中构造函数使用的超级学习教程

    “完全掌握C++编程中构造函数使用的超级学习教程”是一篇涵盖了C++构造函数相关知识的教程,它可以帮助读者全面了解构造函数的概念、用法和设计模式等,并通过示例帮助读者更好地掌握构造函数的使用方法和注意事项。 下面是完整攻略: 一、构造函数概述 1.构造函数的定义 构造函数是一种特殊的成员函数,它在对象创建时自动调用,并完成对象的初始化工作。 2.构造函数的分…

    C 2023年5月22日
    00
  • C语言传递需要初始化的字符串

    首先,需要理解的是,在C语言中,字符串实际上是以字符数组的形式存储的。而字符数组除了可以通过静态初始化初始化外,也可以通过动态初始化来进行初始化。 而如果需要将一个需要初始化的字符串传递给函数,一般情况下需要使用动态初始化的方式。具体而言,需要使用字符数组变量来存储字符串,并在使用的时候将该字符数组变量作为函数参数传递。 以下是一个简单的示例,展示如何使用字…

    C 2023年5月9日
    00
  • C++ TCP网络编程详细讲解

    C++ TCP网络编程详细讲解 简介 TCP网络编程是指基于传输控制协议(TCP)实现的网络通信,其主要特点是数据传输稳定可靠,适用于对数据传输要求较高的应用场景。在C++中,我们可以使用一些网络编程库(如Boost.Asio、Winsock等)来实现TCP网络编程。 步骤 1. 创建socket 在进行TCP网络编程时,我们需要先创建一个socket,通过…

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