iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >【面试心得】C++ 线程池总结
  • 190
分享到

【面试心得】C++ 线程池总结

c++ 2023-09-12 07:09:20 190人浏览 八月长安
摘要

什么是线程池 线程池(Thread Pool)是一种多线程编程的设计模式,它用于管理和复用线程,以有效地执行并发任务。线程池由一组预创建的线程组成,这些线程在需要时被分配来执行任务。线程池的核心思想是将线程的创建、销毁和管理工作从任务执行中

什么是线程池

线程池(Thread Pool)是一种多线程编程设计模式,它用于管理和复用线程,以有效地执行并发任务。线程池由一组预创建的线程组成,这些线程在需要时被分配来执行任务。线程池的核心思想是将线程的创建、销毁和管理工作从任务执行中分离出来,从而提高性能、资源利用率和代码可维护性。

线程池的主要目标是解决以下问题:

  1. 减少线程创建和销毁的开销: 在多线程应用程序中,频繁地创建和销毁线程会导致额外的开销,包括内存分配、上下文切换等。线程池在应用程序启动时创建一组线程,并在任务完成后不立即销毁它们,而是将它们保持在池中以供重用。

  2. 控制并发度: 线程池允许您限制同时执行的线程数量,从而控制系统的并发度。这有助于避免过多的并发线程导致系统资源不足或性能下降的问题。

  3. 提高系统的稳定性和可靠性: 通过管理线程的生命周期,线程池可以提高系统的稳定性,避免因线程创建失败或线程泄漏而导致的问题。

  4. 提高代码可维护性: 使用线程池将任务的执行与线程管理分离,使代码更清晰和可维护。您可以专注于任务的逻辑,而不必担心线程的创建和销毁。

  5. 提高性能: 线程池可以提高多核处理器的利用率,充分利用可用的计算资源,从而加速任务的执行。

总之,线程池是一种有助于管理多线程应用程序的机制,它可以提高性能、资源利用率和代码可维护性,同时降低了多线程编程的复杂性。这就是为什么在许多多线程应用程序中使用线程池的原因。

线程池工作原理

  1. 初始化: 在线程池启动时,会创建一定数量的线程。这些线程通常被称为工作线程。线程池还会创建一个任务队列,用于存储待执行的任务。

  2. 任务提交: 当应用程序有任务需要执行时,它可以将任务提交到线程池。这些任务通常表示为可调用的函数对象(函数指针、Lambda表达式等)。任务提交后,线程池将任务放入任务队列中等待执行。

  3. 任务调度: 线程池中的工作线程会循环地从任务队列中获取任务。一旦工作线程获取到任务,它就会执行该任务。如果没有可用任务,工作线程会等待,直到有任务可执行。

  4. 任务执行: 工作线程执行从任务队列中获取的任务。任务可以并行执行,因为线程池中有多个工作线程,每个工作线程都可以执行不同的任务。

  5. 任务完成: 任务执行完成后,工作线程可以继续从任务队列中获取下一个任务,或者根据线程池的策略决定是否保持线程处于等待状态以等待更多任务。

  6. 线程复用: 工作线程在执行完任务后不会立即销毁,而是返回线程池中等待下一个任务。这样可以减少线程创建和销毁的开销,并提高性能。

  7. 线程池管理: 线程池通常具有管理功能,可以控制线程的数量、动态调整线程池大小、处理异常、记录日志等。这些管理功能有助于线程池的稳定性和性能优化

  8. 任务完成通知: 通常,线程池允许应用程序检测任务是否完成,并获取任务的返回结果。这可以通过各种机制实现,如回调函数、Future/Promise等。

线程池的工作原理允许多个任务在一组工作线程上并发执行,从而提高了系统的性能和资源利用率。线程池还可以根据需要动态调整线程的数量,以适应不同的工作负载。这使得线程池成为处理并发任务的强大工具

保障线程池的线程安全

  1. 任务队列的互斥锁: 任务队列是线程池中的关键资源,因此需要使用互斥(Mutex)来保护它,确保只有一个线程能够访问或修改任务队列。这样可以避免多个线程同时向队列添加或删除任务而导致的问题。

  2. 条件变量: 除了互斥锁,使用条件变量(Condition Variable)来通知等待任务的线程有新任务可执行。条件变量允许线程等待某个条件满足后再继续执行,这在任务队列为空时非常有用。

  3. 线程池状态管理: 维护线程池的状态,例如标识线程池是否处于运行状态、是否正在销毁等。在操作线程池状态时需要加锁,以确保线程安全。

  4. 资源的合理共享: 确保线程池中的线程在共享资源时进行适当的同步。避免数据竞争问题,如多个线程同时修改同一个变量。

  5. 异常处理: 考虑线程中可能出现的异常情况,特别是在任务执行时,确保异常不会导致线程池崩溃。可以使用 try-catch 块捕获异常,记录日志或采取适当的措施。

  6. 资源管理: 确保线程池中的线程在退出时释放资源,如内存、文件句柄等。防止资源泄漏。

  7. 使用原子操作: 在需要对共享变量进行增减等操作时,使用原子操作,以确保操作的原子性,避免竞态条件。

代码实现

版本一

xthread_pool.h

#pragma once#include #include #include #include #include #include class XTask{public:    virtual int Run() = 0;    std::function is_exit = nullptr;};class XThreadPool{public:    //    /// 初始化线程池    /// @para num 线程数量    void Init(int num);    //    /// 启动所有线程,必须先调用Init    void Start();    //    /// 线程池退出    void Stop();    void AddTask(XTask* task);    XTask* GetTask();    //线程池是否退出    bool is_exit() { return is_exit_; }    int task_run_count() { return task_run_count_; }private:    //线程池线程的入口函数    void Run() ;    int thread_num_ = 0;//线程数量    std::mutex mux_;    std::vector threads_;    std::list tasks_;    std::condition_variable cv_;    bool is_exit_ = false; //线程池退出    //正在运行的任务数量,线程安全    std::atomic task_run_count_ = {0};};

 xthread_pool.cpp

#include "xthread_pool.h"#include using namespace std;///// 初始化线程池/// @para num 线程数量void XThreadPool::Init(int num){    unique_lock lock(mux_);    this->thread_num_ = num;    cout << "Thread pool Init " << num << endl;}///// 启动所有线程,必须先调用Initvoid XThreadPool::Start(){    unique_lock lock(mux_);    if (thread_num_ <= 0)    {        cerr << "Please Init XThreadPool" << endl;        return;    }    if (!threads_.empty())    {        cerr << "Thread pool has start!" << endl;        return;    }    //启动线程    for (int i = 0; i < thread_num_; i++)    {        auto th = new thread(&XThreadPool::Run, this);        threads_.push_back(th);    }}///// 线程池退出void XThreadPool::Stop(){    is_exit_ = true;    cv_.notify_all();    for (auto& th : threads_)    {        th->join();    }    unique_lock lock(mux_);    threads_.clear();}//线程池线程的入口函数void XThreadPool::Run(){    cout << "begin XThreadPool Run " << this_thread::get_id() << endl;    while (!is_exit())    {        auto task = GetTask();        if (!task)continue;        ++task_run_count_;        try        {            task->Run();        }        catch (...)        {        }        --task_run_count_;    }    cout << "end XThreadPool Run " << this_thread::get_id() << endl;}void XThreadPool::AddTask(XTask* task){    unique_lock lock(mux_);    tasks_.push_back(task);    task->is_exit = [this] {return is_exit(); };    lock.unlock();    cv_.notify_one();}XTask* XThreadPool::GetTask(){    unique_lock lock(mux_);    if (tasks_.empty())    {        cv_.wait(lock);    }    if (is_exit())        return nullptr;    if (tasks_.empty())        return nullptr;    auto task = tasks_.front();    tasks_.pop_front();    return task;}

main.cpp 

#include "xthread_pool.h"#include using namespace std;class MyTask :public XTask{public:    int Run()    {        cout << "================================================" << endl;        cout << this_thread::get_id()<<" Mytask " << name << endl;        cout << "================================================" << endl;        for (int i = 0; i < 10; i++)        {            if (is_exit())break;            cout << "." << flush;            this_thread::sleep_for(500ms);        }        return 0;    }    std::string name = "";};int main(int arGC, char* argv[]){      XThreadPool pool;    pool.Init(16);    pool.Start();    MyTask task1;    task1.name = "test name 001";    pool.AddTask(&task1);    MyTask task2;    task2.name = "test name 002";    pool.AddTask(&task2);    this_thread::sleep_for(100ms);    cout << "task run  count = " << pool.task_run_count() << endl;    this_thread::sleep_for(1s);    pool.Stop();    cout << "task run  count = " << pool.task_run_count() << endl;    getchar();    return 0;}

版本二(智能指针)

xthread_pool.h

#pragma once#include #include #include #include #include #include class XTask{public:    virtual int Run() = 0;    std::function is_exit = nullptr;};class XThreadPool{public:    //    /// 初始化线程池    /// @para num 线程数量    void Init(int num);    //    /// 启动所有线程,必须先调用Init    void Start();    //    /// 线程池退出    void Stop();    //void AddTask(XTask* task);    void AddTask(std::shared_ptr task);    std::shared_ptr GetTask();    //线程池是否退出    bool is_exit() { return is_exit_; }    int task_run_count() { return task_run_count_; }private:    //线程池线程的入口函数    void Run() ;    int thread_num_ = 0;//线程数量    std::mutex mux_;    //std::vector threads_;    //线程列表 指针指针版本    std::vector< std::shared_ptr > threads_;    //std::list tasks_;    std::list > tasks_;        std::condition_variable cv_;    bool is_exit_ = false; //线程池退出    //正在运行的任务数量,线程安全    std::atomic task_run_count_ = {0};};

xthread_pool.cpp 

#include "xthread_pool.h"#include using namespace std;///// 初始化线程池/// @para num 线程数量void XThreadPool::Init(int num){    unique_lock lock(mux_);    this->thread_num_ = num;    cout << "Thread pool Init " << num << endl;}///// 启动所有线程,必须先调用Initvoid XThreadPool::Start(){    unique_lock lock(mux_);    if (thread_num_ <= 0)    {        cerr << "Please Init XThreadPool" << endl;        return;    }    if (!threads_.empty())    {        cerr << "Thread pool has start!" << endl;        return;    }    //启动线程    for (int i = 0; i < thread_num_; i++)    {        //auto th = new thread(&XThreadPool::Run, this);        auto th = make_shared(&XThreadPool::Run, this);        threads_.push_back(th);    }}///// 线程池退出void XThreadPool::Stop(){    is_exit_ = true;    cv_.notify_all();    for (auto& th : threads_)    {        th->join();    }    unique_lock lock(mux_);    threads_.clear();}//线程池线程的入口函数void XThreadPool::Run(){    cout << "begin XThreadPool Run " << this_thread::get_id() << endl;    while (!is_exit())    {        auto task = GetTask();        if (!task)continue;        ++task_run_count_;        try        {            task->Run();        }        catch (...)        {        }        --task_run_count_;    }    cout << "end XThreadPool Run " << this_thread::get_id() << endl;}void XThreadPool::AddTask(std::shared_ptr task){    unique_lock lock(mux_);    tasks_.push_back(task);    task->is_exit = [this] {return is_exit(); };    lock.unlock();    cv_.notify_one();}std::shared_ptr XThreadPool::GetTask(){    unique_lock lock(mux_);    if (tasks_.empty())    {        cv_.wait(lock);    }    if (is_exit())        return nullptr;    if (tasks_.empty())        return nullptr;    auto task = tasks_.front();    tasks_.pop_front();    return task;}

 main.cpp

#include "xthread_pool.h"#include using namespace std;class MyTask :public XTask{public:    int Run()    {        cout << "================================================" << endl;        cout << this_thread::get_id()<<" Mytask " << name << endl;        cout << "================================================" << endl;        for (int i = 0; i < 10; i++)        {            if (is_exit())break;            cout << "." << flush;            this_thread::sleep_for(500ms);        }        return 0;    }    std::string name = "";};int main(int argc, char* argv[]){      XThreadPool pool;    pool.Init(16);    pool.Start();    {        auto task3 = make_shared();        task3->name = "test shared 003";        pool.AddTask(task3);        auto task4 = make_shared();        task4->name = "test shared 004";        pool.AddTask(task4);    }    this_thread::sleep_for(100ms);    cout << "task run  count = " << pool.task_run_count() << endl;    this_thread::sleep_for(1s);    pool.Stop();    cout << "task run  count = " << pool.task_run_count() << endl;    getchar();    return 0;}

来源地址:https://blog.csdn.net/weixin_42809675/article/details/132802041

--结束END--

本文标题: 【面试心得】C++ 线程池总结

本文链接: https://www.lsjlt.com/news/404132.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 【面试心得】C++ 线程池总结
    什么是线程池 线程池(Thread Pool)是一种多线程编程的设计模式,它用于管理和复用线程,以有效地执行并发任务。线程池由一组预创建的线程组成,这些线程在需要时被分配来执行任务。线程池的核心思想是将线程的创建、销毁和管理工作从任务执行中...
    99+
    2023-09-12
    c++
  • Java线程池高频面试题总结
    目录1、在启动线程时,为什么要通过调用方法start执行方法run,而不能直接执行方法run?2、方法sleep、join和yield的区别有哪些?3.为什么方法wait、notif...
    99+
    2024-04-02
  • Java 线程池全面总结与详解
    目录原理阻塞队列有界阻塞队列无界阻塞队列同步移交队列实现类分析使用Executors创建线程池线程池关闭线程池是很常用的并发框架,几乎所有需要异步和并发处理任务的程序都可用到线程池。...
    99+
    2024-04-02
  • Java线程池全面知识点总结
    本篇内容介绍了“Java线程池全面知识点总结”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!原理线程池的原理非常简单,这里用处理流程来概括:线...
    99+
    2023-06-25
  • Java线程池实现原理总结
    目录一、线程池参数二、线程池执行流程三、四种现成的线程池要理解实现原理,必须把线程池的几个参数彻底搞懂,不要死记硬背 一、线程池参数 1、corePoolSize(必填):核心线程数...
    99+
    2024-04-02
  • Spring Boot线程池使用的一些实用心得
    目录前言使用步骤用postmain或者其他工具来多次测试请求一下总结前言 前两天做项目的时候,想提高一下插入表的性能优化,因为是两张表,先插旧的表,紧接着插新的表,一万多条数据就有...
    99+
    2024-04-02
  • Java并发编程面试之线程池
    目录什么是线程池线程池好处线程池的执行流程怎么用线程池corePoolSizemaximumPoolSizekeepAliveTimeunitworkQueuethreadFacto...
    99+
    2024-04-02
  • 最新天猫面试题(含总结):线程池+并发编程+分布式设计+中间件
    一面:HashMap实现原理,ConcurrentHashMap实现原理红黑树,为什么允许局部不平衡TCP,UDP区别,为什么可靠和不可靠一次HTTP请求的全过程,包括域名解析、定位主机等TCP三次握手MySQL事务是什么?四大特性,四大隔...
    99+
    2023-06-05
  • 精心整理总结的Python自动化测试面试题
    目录1、自动化代码中,用到了哪些设计模式2、什么是断言( Assert) 3、什么是web自动化测试4、什么是Selenium?5、写出Selenium中你最熟悉的接口或类6、元素定...
    99+
    2023-02-17
    python自动化测试面试题 python面试题
  • Android的线程、多线程和线程池面试题有哪些
    这篇“Android的线程、多线程和线程池面试题有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android的线程、多...
    99+
    2023-06-04
  • Java线程池必知必会知识点总结
    目录1、线程数使用开发规约2、 ThreadPoolExecutor源码1. 构造函数2.核心参数3.execute()方法3、线程池的工作流程4、Executors创建返回Thre...
    99+
    2024-04-02
  • 浅谈Spring @Async异步线程池用法总结
    本文介绍了Spring @Async异步线程池用法总结,分享给大家,希望对大家有帮助1. TaskExecutorspring异步线程池的接口类,其实质是Java.util.concurrent.ExecutorSpring 已经实现的异常...
    99+
    2023-05-31
    async spring 线程池
  • java线程池使用及原理面试题
    目录引导语1、说说你对线程池的理解?2、ThreadPoolExecutor、Executor、ExecutorService、Runnable、Callable、FutureTas...
    99+
    2024-04-02
  • Linux运维工程师面试题总结
    本篇内容介绍了“Linux运维工程师面试题总结”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、Linux操作系统知识常见的Linux发行版...
    99+
    2023-06-13
  • 软件实施工程师面试总结
    一、远程控制windows服务器的方法 1.向日葵 2.windows自带的远程桌面功能 3.todesk远程第三方 二、 Linux 命令: cd /home 进入 '/ home' 目录' c...
    99+
    2023-09-04
    数据库 服务器 运维
  • Java经典面试题汇总--多线程
    目录1.并行和并发有什么区别?2.线程和进程的区别?3.守护线程是什么?4.实现多线程的方式有哪些?5.说一下runnable和callable有什么区别?6.sleep()和wai...
    99+
    2024-04-02
  • Java经典面试题汇总:多线程
    目录1. 并行和并发有什么区别?2.线程和进程的区别?3.守护线程是什么?4.实现多线程的方式有哪些?5.说一下runnable和callable有什么区别?6.sleep...
    99+
    2024-04-02
  • Java多线程知识点全面总结
    目录Java多线程知识点总结(1)什么是进程什么是线程?(2)多线程的运行状态(3)线程的创建和使用(4)Runnable 接口实现多线程(5)Callable接口实现多线程多线程常...
    99+
    2024-04-02
  • C语言面试常见考点排序总结
    排序算法有两块比较重要的知识点 内存消耗 :算法的内存消耗可以通过空间复杂度来衡量,排序算法也不例外。不过,针对排序算法的空间复杂度,有一个概念是原地排序。原地排序算法是指...
    99+
    2024-04-02
  • 面试必问:掌握Load算法,PHP编程更得心应手!
    在PHP编程中,Load算法是一个非常重要的概念。它可以帮助我们更好地理解服务器负载以及如何优化PHP应用程序。在本文中,我们将深入探讨Load算法的概念、计算方法以及如何在PHP中应用它。 什么是Load算法? Load算法是一个用于计...
    99+
    2023-08-15
    面试 load 编程算法
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作