一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着 监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利 用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。我们去处理任务时,一个任务对应一个创建一个线程进行处理,效率是比较低的。我们可以预先创建一批线程,任务队列里没有任务的时候,每个线程都休眠,当队里中有任务的时候,就可以环形线程进行处理了。唤醒线程的成本比创建整个线程的成本小,这就是线程池的逻辑思想2.线程池的使用场景-- 需要大量的线程来完成任务,且完成任务的时间比较短。-- 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。-- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。3.实现线程池一.线程的封装Thread.hppThread类主要成员变量是线程名,函数,线程参数,参数ID以及对应编号Thread类提供了一个无参构造,完成对成员变量name的赋值。同时,对外主要提供了start接口和join接口,对于join接口就是线程等待,而对于start接口就是创建线程的接口,在外部如果调用的话我们需要传入对应的函数以及线程对应的参数。#pragma once#include <pthread.h>#include <iostream>#include <cassert>#include <string>#include <functional>namespace ThreadNs{ typedef std::function<void*(void*)> func_t; const int num =1024; class Thread { private: static void* start_routine(void*args) { Thread* _this = static_cast<Thread*>(args); return _this->callback(); } public: Thread() { char namebuffer[num]; snprintf(namebuffer,sizeof namebuffer,"thread-%d",threadnum++); name_ = namebuffer; } void start(func_t func,void*args = nullptr) { func_ = func; args_ = args; int n = pthread_create(&tid_,nullptr,start_routine,this); assert(n==0); (void)n; } void join() { int n = pthread_join(tid_,nullptr); assert(n==0); (void)n; } std::string threadname() { return name_; } ~Thread() {} void* callback() { return func_(args_); } private: std::string name_; func_t func_; void *args_; pthread_t tid_; static int threadnum; }; int Thread::threadnum = 1;} 对于任务队列,可以由多个线程进行访问所以要加锁保护,下面是对锁的封装:LockGuard.hpp:#include <iostream>#include <mutex>class Mutex{public: Mutex(pthread_mutex_t*lock_p=nullptr) :lock_p_(lock_p) {} void lock() { if(lock_p_) pthread_mutex_lock(lock_p_); } void unlock() { if(lock_p_) pthread_mutex_unlock(lock_p_); } ~Mutex() {}private: pthread_mutex_t * lock_p_;};class LockGuard{public: LockGuard(pthread_mutex_t*mutex) :mutex_(mutex) { mutex_.lock(); } ~LockGuard() { mutex_.unlock(); }private: Mutex mutex_;};创建一批线程时,我们需要实现线程的调用函数static void*handlerTask,之所以是静态的,是因为我们要把这个运行函数传递给Thread类中的func_,不能有this指针,所以是静态成员函数。而没有this指针,我们无法访问ThreadPool里面的成员变量,所以需要封装接口供其调用。ThreadPool.hpp#pragma once#include "Thread.hpp"#include "LockGuard.hpp"#include <vector>#include <queue>#include <pthread.h>#include <mutex>#include <unistd.h>using namespace ThreadNs;const int gnum = 3;template <class T>class ThreadPool; template <class T>class ThreadData{public: ThreadPool<T> *threadpool; std::string name;public: ThreadData(ThreadPool<T> *tp, const std::string &n) : threadpool(tp), name(n) { }};template <class T>class ThreadPool{private: static void *handlerTask(void *args) { ThreadData<T> *td = (ThreadData<T> *)args; ThreadPool<T> *threadpool = static_cast<ThreadPool<T> *>(args); while (true) { T t; { LockGuard lockguard(td->threadpool->mutex()); while(td->threadpool->isQueueEmpty()) { td->threadpool->threadWait(); } t = td->threadpool->pop(); } std::cout << td->name << " 获取了一个任务" << t.toTaskString() << "并处理完成,结果是: " << t() << std::endl; } delete td; return nullptr; }public: void lockQueue() { pthread_mutex_lock(&_mutex); } void unlockQueue() { pthread_mutex_unlock(&_mutex); } bool isQueueEmpty() { return _task_queue.empty(); } void threadWait() { pthread_cond_wait(&_cond, &_mutex); } T pop() { T t = _task_queue.front(); _task_queue.pop(); return t; } void Push(const T &in) { LockGuard lockguard(&_mutex); _task_queue.push(in); pthread_cond_signal(&_cond); } pthread_mutex_t *mutex() { return &_mutex; } public: ThreadPool(const int &num = gnum) : _num(num) { pthread_mutex_init(&_mutex, nullptr); pthread_cond_init(&_cond, nullptr); for (int i = 0; i < _num; i++) { _threads.push_back(new Thread()); } } void run() { for (const auto &t : _threads) { ThreadData<T> *td = new ThreadData<T>(this, t->threadname()); t->start(handlerTask, td); std::cout << t->threadname() << "start..." << std::endl; } } ~ThreadPool() { pthread_mutex_destroy(&_mutex); pthread_cond_destroy(&_cond); for (const auto &t : _threads) delete t; }private: int _num; std::vector<Thread *> _threads; std::queue<T> _task_queue; pthread_mutex_t _mutex; pthread_cond_t _cond;};因为线程池中存储的任务是任意的,所以需要将线程池进行模板化,下面引入任务组件Task.hpp#pragma once#include <iostream>#include <functional>class Task{ using func_t = std::function<int(int,int ,char)>;public: Task(){} Task(int x,int y,char op,func_t func) :_x(x),_y(y),_op(op),_callback(func) {} std::string operator()() { int result = _callback(_x,_y,_op); char buffer[1024]; snprintf(buffer,sizeof buffer,"%d %c %d = %d",_x,_op,_y,result); return buffer; } std::string toTaskString() { char buffer[1024]; snprintf(buffer,sizeof buffer,"%d %c %d = ?",_x,_op,_y); return buffer; }private: int _x; int _y; char _op; func_t _callback;}; const std::string oper = "+-*/%";int mymath(int x,int y,char op){ int result = 0; switch(op) { case '+': result = x+y; break; case '-': result = x-y; break; case '*': result = x*y; break; case '/': if(y==0) { std::cerr<<"div zero error!"<<std::endl; result = -1; } else { result = x/y; } break; case '%': if(y==0) { std::cerr<<"mod zero error!"<<std::endl; result = -1; } else { result = x%y; } break; default: break; } return result;}main.cpp#include "ThreadPool.hpp"#include "Thread.hpp"#include "Task.hpp"#include <unistd.h>#include <ctime>int main(){ ThreadPool<Task>* tp = new ThreadPool<Task>(); tp->run(); srand(time(0)); int x,y; char op; while(true) { x = rand()%10+1; y = rand()%20+1; op =oper[rand()%oper.size()]; Task t(x,y,op,mymath); tp->Push(t); sleep(1); } return 0;}文章知识点与官方知识档案匹配,可进一步学习相关知识CS入门技能树Linux入门初识Linux35683 人正在系统学习中阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作bite-ccc关注854『Linux』第九讲:Linux多线程详解(六 - 完结)_ 线程池 | 读写锁枫叶先生的博客 678线程池 | 读写锁详解Linux组件之线程池Ricardo2的博客 357手写线程池4 条评论微风撞见云热评支持博主优质文章,讲解得非常透彻,解答了我许多疑惑!写评论Linux —— 线程池M的博客 4395一、什么是线程池二、线程池的优点三、线程池的应用四、实现一个简单的线程池五、单例模式1. 饿汉实现方式2. 懒汉实现方式3. 单例模式实现线程池(懒汉方式)六、其他常见的各种锁【Linux线程池】qq_68472674的博客 129Linux线程池linux 实现一个简单的线程池及工作03-30linux 实现一个简单的线程池及工作 本实例演示了线程池的创建使用线程池【Linux】Man9o 5151. 引入 2. 应用 3. 实现 封装线程 封装线程池 线程函数 生产消费逻辑 互斥锁 条件变量 线程函数 主线程 测试1 4. 优化 5. 日志 日志的重要性 实现 日志级别 提取参数 stdarg.h 头文件 日志文件 懒汉实现单例模式 什么是懒汉模式 什么是单例模式 实现linux c线程池10-15linux pthreadpool实现和线程池的用处 简单易懂 互斥和信号量使用Linux--线程池与进程池及线程池的简单实现热门推荐sayhello_world的博客 1万+池由于服务器的硬件资源“充裕”,那么提高服务器性能的一个很直接的方法就是以空间换时间,即“浪费”服务器的硬件资源,以换取其运行效率。这就是池的概念。池是一组资源的集合,这组资源在服务器启动之初就被创建并初始化,这称为静态资源分配。当服务器进入正式运行阶段,即开始处理客户请求的时候,如果它需要相关的资源,就可以直接从池中获取,无需动态分配。很显然,直接从池中取得所需资源比动态分配资源的速度要快得多,因Linux下C线程池实现05-05在Linux下用C写的一个简易线程池。系统是RedHat 9,gcc版本"gcc version 4.1.2 20071124 (Red Hat 4.1.2-42)"。文件夹里的源码是按工程组织好的,在文件夹下的test目录下面有一个小的测试程序和Makefile,编译后即可运行。测试过添加了300多个任务,同时并发256个线程,运行正常。不过在停止线程(包括系统空闲时减少线程数量)方面还没完全实现好,需要用的话可以自己添加或者暂时先不管这方面。 补充:利用7号中午的时间已经把上述的问题解决了,现已能正确的根据当前任务数动态减少线程。不过现在不方便也不想上传了,需要的话可以通过源文件中的邮箱联系我或在以后去google code下载。如果各位有好的建议,欢迎通过邮件联系。 -------- by vincentlinux线程池,c语言实现01-06linux线程池,c语言实现,只是文件后缀名用的是cpp方便在qt里面测试,两种版本,都是参考网上的资料做了一些处理之后的Linux线程池11-24在Linux下运用Boost来实现的一个线程池,方便而且高效linux线程池创建c实现07-23linux线程池创建c实现 linux线程池创建c实现 linux线程池创建c实现 linux线程池创建c实现 linux线程池创建c实现 linux线程池创建c实现Linux 线程池源码分析11-12非常详细的线程池函数接口分析,可以帮助初学者加深对线程池的理解,更好的去把线程池运用到实例中去,线程池就是多个线程组合在一起的集合,就像一家公司一样,由多个员工组成的一个集合,当有任务时, 这些线程就会去处理任务,当没有任务时,线程就会休息。Linux下线程池(ThreadPool)qq_56999918的博客 796再这里实现的是一个简单的线程池,再这个线程池当中有一个任务队列,线程从任务队列当中提前任务,已经若干个线程,一开始再特点的条件变量下进行等待。线程池中的线程去这个任务队列当中拿任务的前提必须是任务队列当中要有任务,如果此时我们只使用互斥锁那么就有可能出现互斥锁一直被一个线程占用着,这是不合理的因此我们需要引入条件变量。此时线程池中的线程只需要从任务队列中拿到任务然后执行Run方法即可.下面我们来看一下主线程的执行逻辑:主线程主要负责通过线程池提供的Push方法将任务放入到任务队列当中即可。Linux 线程池09-03可实现线程池的基本功能,用多线程实现对文件的读取,可读取大文件,经实测代码没有任何bugLinux线程池代码.zip11-14基于Linux的线程池源代码linux线程池代码(c++实现)04-15linux线程池代码(c++实现) 分两部: 1、创建线程池 2、创建任务、加入线程池 可以参考使用linux线程池实现数据拷贝05-141、使用线程池的概念,利用linux多线程对一个目录以及目录中嵌套的文件进行拷贝,保证拷贝数据的完整性,并且多线程并发进行拷贝,节约程序运行时间,提高工作效率。 2、涉及linux文件IO、linux多线程&线程池、数据...linux线程池原理最新发布07-28Linux线程池的原理是通过任务队列和线程队列的配合来实现的。任务队列用于存储需要处理的任务,而线程队列则用于存储可用的线程。当有任务需要处理时,线程池会从线程队列中获取一个空闲线程来执行任务。当任务执行完毕后,线程会返回线程队列,等待下一个任务的到来。 线程池的初始化过程包括申请内存、初始化锁和信号量、设置最大线程数量、最大空闲线程数量等。在初始化完成后,线程池就可以开始接收任务并进行处理了。 在任务执行函数中,线程会从任务队列中获取任务,并执行相应的操作。当任务执行完毕后,线程会继续等待下一个任务的到来。需要注意的是,在线程退出后,线程节点的内存并没有归还给操作系统,这是因为设计相对简单,可以根据需要进行改进。 总结来说,Linux线程池的原理是通过任务队列和线程队列的配合来实现任务的分配和执行。这种设计可以提高程序的效率和性能,同时也可以避免频繁地创建和销毁线程。112233#### 引用[.reference_title] - *1* [linux下c语言版线程池](https://blog.csdn.net/weixin_42398658/article/details/123849826)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Linux线程池的原理及实现](https://blog.csdn.net/weixin_44344462/article/details/96432009)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]