C++实现一个简单的线程池的示例代码

下面是实现简单线程池的代码攻略。

什么是线程池?

线程池是一种用于管理多线程执行的机制,允许在需要时提供可分配的工作线程集中的线程。使用线程池的好处是可以减少线程的创建和销毁次数,避免线程频繁创建和销毁所带来的开销,也可以避免同时开启大量的线程造成系统资源的过度占用。在实际生产环境中,线程池通常具有限制线程数量、任务队列、线程管理等功能。

C++实现线程池的示例代码

下面我们以C++为例,使用C++11中的线程库,实现一个简单的线程池。主要的类和函数有:

  • std::thread:C++11中的线程类,用于创建新线程。

  • std::mutex:C++11中的互斥量类,用于线程间的互斥访问。

  • std::condition_variable:C++11中的条件变量类,用于线程间的同步。

  • std::function:C++11中的函数类,用于存储任意可调用对象,包括函数指针、成员函数指针、lambda表达式等。

  • std::queue:C++中的队列类,用于存储任务列表。

下面是一个简单的线程池实现代码。该线程池的主要功能包括添加任务、执行任务和关闭线程池。

#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <queue>
#include <vector>

class ThreadPool {
public:
    ThreadPool(int num_threads) : is_running_(true) {
        for (int i = 0; i < num_threads; ++i) {
            threads_.emplace_back(std::bind(&ThreadPool::ThreadFunc, this));
        }
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            is_running_ = false;
        }
        cv_.notify_all();

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

    void AddTask(std::function<void()> task_func) {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        tasks_.push(std::move(task_func));
        cv_.notify_one();
    }

private:
    void ThreadFunc() {
        while (is_running_) {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            cv_.wait(lock, [this] { return !tasks_.empty() || !is_running_; });

            if (!is_running_) {
                break;
            }

            auto task = std::move(tasks_.front());
            tasks_.pop();

            lock.unlock();

            task();
        }
    }

    bool is_running_;
    std::mutex queue_mutex_;
    std::condition_variable cv_;
    std::queue<std::function<void()>> tasks_;
    std::vector<std::thread> threads_;
};

上述代码中,创建线程池时,需要指定线程池的线程数量,然后创建相应数量的工作线程。每个工作线程都执行ThreadFunc()函数中的操作。ThreadFunc()函数中不断地查询任务队列,如果队列为空就等待,直到队列中有新的任务进来或者线程池已经被终止。

当添加新任务时,需要将任务函数存储到任务队列中,并唤醒一个等待的线程执行任务。

关闭线程池时,需要将每个工作线程终止,并删除队列中尚未执行的任务。

示例代码说明

这里给出两个简单的示例代码说明:

  • 示例1:使用线程池求和
#include <iostream>
#include "ThreadPool.h"

int Sum(int a, int b) {
    std::cout << "Thread " << std::this_thread::get_id() << ": Sum a and b\n";
    return a + b;
}

void main() {
    ThreadPool thread_pool(4);

    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    auto func = [](int n) { return n * n; };

    int sum = 0;
    for (auto n : numbers) {
        thread_pool.AddTask([&sum, n]() { sum += n; });
    }

    auto result_future = thread_pool.AddTask(std::bind(Sum, 100, 200));
    std::cout << "Thread " << std::this_thread::get_id() << ": Submi task for Sum(100, 200)\n";

    for (auto n : numbers) {
        thread_pool.AddTask(std::bind([&sum](int n) { sum += n; }, func(n)));
    }

    std::cout << "Thread " << std::this_thread::get_id() << ": Waiting for result\n";

    std::cout << "Result: " << sum + result_future.get() << std::endl;
}

上述代码中,首先创建了一个线程池thread_pool,然后向线程池中添加了多个任务,如对数列中的每个数求平方和,以及调用Sum函数计算100和200的和。其中,Sum函数是一个简单的计算两个参数和的函数。

可以看到,添加任务时,可以使用lambda表达式、std::functionstd::bind等方式来封装任务函数。使用线程池可以减少代码中的线程创建及管理开销。

  • 示例2:使用线程池处理图像
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include "ThreadPool.h"

void ProcessImage(cv::Mat& image) {
    int channels = image.channels();
    int n_rows = image.rows;
    int n_cols = image.cols * channels;

    for (int i = 0; i < n_rows; ++i) {
        uchar* data = image.ptr<uchar>(i);
        for (int j = 0; j < n_cols; ++j) {
            data[j] = 255 - data[j];
        }
    }
}

void main() {
    cv::Mat image = cv::imread("sample.jpg");
    if (image.empty()) {
        std::cout << "Cannot read image file" << std::endl;
        return;
    }

    ThreadPool thread_pool(4);

    std::vector<cv::Mat> image_parts;
    int num_parts = 4;
    int part_rows = image.rows / num_parts;

    for (int i = 0; i < num_parts; ++i) {
        cv::Mat image_part(image, cv::Rect(0, i * part_rows, image.cols, part_rows));
        image_parts.push_back(image_part);
    }

    std::vector<std::future<void>> results;
    for (auto& part : image_parts) {
        results.push_back(thread_pool.AddTask(std::bind(ProcessImage, std::ref(part))));
    }

    for (auto& result : results) {
        result.get();
    }

    cv::imwrite("result.jpg", image);
}

这是一个简单的图像处理示例,在使用原始方式处理图像时,需要在循环中遍历图像的每个像素进行处理,这样的操作需要较长的时间。而在使用线程池方式处理图像时,可以将图像分成几个部分,让每个线程单独处理一部分图像,然后等处理完成后合并成完整的图像。这样,可以大大缩短图像处理时间。

在示例代码中,首先读取一张图片sample.jpg,然后将图片分成4部分,并向线程池中添加图像处理任务。任务处理完成后,等待各个任务执行完毕,将处理后的图像保存为result.jpg。可以看到,使用线程池处理图像需要创建很少的线程,且线程资源得到高效的利用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++实现一个简单的线程池的示例代码 - Python技术站

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

相关文章

  • C语言实现动态顺序表的示例代码

    下面是关于C语言实现动态顺序表的示例代码的完整攻略。 什么是动态顺序表? 动态顺序表是一种可以动态扩容的线性表,它的底层实现采用数组实现。相对于静态顺序表而言,在使用过程中更加灵活,可以在容量不够时自动扩容,节省了空间,同时又可以随着数据的增加而自动增长容量,保证数据的完整性。 如何实现动态顺序表? 1. 动态顺序表实现的数据结构 动态顺序表的底层数据结构是…

    C 2023年5月23日
    00
  • jQuery简单验证上传文件大小及类型的方法

    下面就是对于“jQuery简单验证上传文件大小及类型的方法”的详细攻略。 什么是文件验证? 文件上传是Web开发中常用的功能,但是常常需要验证上传文件的大小、类型等信息。通过对文件进行验证,可以避免上传恶意或者不支持的文件类型,也可以限制文件的大小,避免系统资源浪费,提高系统的安全性和稳定性。 如何使用jQuery验证上传文件大小及类型? 在jQuery中,…

    C 2023年5月23日
    00
  • 华硕X450C系列笔记本怎么拆机清灰?

    下面是关于华硕X450C系列笔记本拆机清灰的完整攻略: 1. 准备工具和环境 在进行拆机清灰之前,我们需要准备好以下工具和环境: 一个适合拆开笔记本电脑的螺丝刀套装 一块软布或清洁刷子 一瓶压缩气罐或吸尘器 一个安静、平坦的操作环境,最好在桌子上放置一块软质材料,例如毯子或厚垫子,以防止刮伤电脑。 2. 确认拆机方式 在进行拆机清灰之前,你需要确定你的笔记本…

    C 2023年5月22日
    00
  • Alibaba Fastjson之超好用的JOSN解析库

    首先需要明确的是,Fastjson是一款由阿里巴巴集团开发的JSON解析库,它由于其灵活、高效、易用等优势,已经成为Java开发领域中使用最广泛的JSON解析库之一。下面,我将结合示例说明,讲解如何使用Fastjson这款超好用的JSON解析库。 1. 引入Fastjson依赖 首先,在使用Fastjson之前,我们需要先将其引入到我们的项目中。我们可以通过…

    C 2023年5月23日
    00
  • 通俗易懂的C++前缀和与差分算法图文示例详解

    通俗易懂的C++前缀和与差分算法图文示例详解 前言 前缀和与差分算法,是在算法中常用的技巧。在许多数据处理问题,通过利用前缀和和差分的方法,可以大大简化问题的复杂度和难度。因此,掌握这两种算法,是每一个学习算法的人必备的基本技能。 本篇文章将详细讲解前缀和与差分算法的基本原理与实现方法,通过简单易懂的图文示例,帮助读者更深入地理解算法的奥妙所在,并提供C++…

    C 2023年5月22日
    00
  • Win10安装中提示错误0xC1900101的多种解决方法

    Win10安装中提示错误0xC1900101的多种解决方法 在 Win10 的升级或安装过程中,可能会遇到报错 “0xC1900101”,该错误通常提示安装过程无法完成,这时我们需要采取相应的解决方法。 下面介绍 “Win10安装中提示错误0xC1900101的多种解决方法”: 解决方法1:更新BIOS 更新BIOS是一种可行的解决方法,因为BIOS更新可以…

    C 2023年5月23日
    00
  • C语言运算符优先级列表(超详细)

    C语言运算符优先级列表(超详细) 前言 在C语言中,运算符的优先级不同,会影响整个表达式的计算结果,因此深入了解运算符的优先级是非常有必要的。本文将给出C语言中各种运算符的优先级列表及说明,以帮助读者更好地掌握C语言的运算符。 运算符优先级列表 运算符 结合性 说明 () [] -> . 从左到右 圆括号,方括号,箭头符(用于结构体指针),点符号(用于…

    C 2023年5月22日
    00
  • word文章中怎么插入数学公式?

    下面是关于在 Word 文章中插入数学公式的完整攻略: 步骤一:安装 Microsoft Office 公式编辑器 可以通过以下步骤进行操作: 打开 Word 文档,从“文件”菜单中选择“选项”。 在弹出的对话框中选择“自定义功能区”选项,并在右侧列表中选择“开发工具”复选框,点击“确定”按钮。 点击“开发工具”菜单,选择“COM 加载项”按钮,在弹出的对话…

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