POCO C++库学习和分析 -- 线程 (二)
POCO C++库学习和分析 -- 线程 (二)
3. 线程池
3.1线程池的基本概念
首先我们来明确线程池的一些概念。
什么是线程池?线程池的好处?
池的英文名:POOL,可以被理解成一个容器。线程池就是放置线程对象的容器。我们知道线程的频繁创建、销毁,是需要耗费一点的系统资源的,如果能够预先创建一系列空线程,在需要使用线程时侯,从线程池里,直接获取IDLE线程,则省去了线程创建的过程,当有频繁的线程出现的时候对性能有比较大的好处,程序执行起来将非常效率。
什么时候推荐使用线程池?
很明显,线程越频繁的被创建和释放,越是能体现出线程池的作用。这时候当然推荐使用线程池。
什么时候不推荐使用线程池?
推荐线程池使用的反面情况喽。
比如长时间运行的线程(线程运行的时间越长,其创建和销毁的开销在其生命周期中比重越低)。
需要永久标识来标识和控制线程,比如想使用专用线程来终止该线程,将其挂起或按名称发现它。因为线程池中的线程都是平等的。
线程池需要具备的元素
- 线程池要有列表,可以用来管理多个线程对象。
- 线程池中的线程,具体执行的内容,可自定义。
- 线程池中的线程,使用完毕后,还能被收回,供下次使用。
- 线程池要提供获取空闲(IDLE)线程方法。当然这个方法可以被封装在线程池中,成为其内部接口。
3.2 Poco中线程池实现
先看一看Poco中内存池的类图吧。
对于Poco中的线程池来说,设计上分成了两层。第一层为ThreadPool,第二层为PooledThread对象。
第一层中,ThreadPool负责管理线程池,定义如下:
class ThreadPool
{
public:ThreadPool(int minCapacity = 2,int maxCapacity = 16,int idleTime = 60,int stackSize = POCO_THREAD_STACK_SIZE);ThreadPool(const std::string& name,int minCapacity = 2,int maxCapacity = 16,int idleTime = 60,int stackSize = POCO_THREAD_STACK_SIZE);~ThreadPool();void addCapacity(int n);int capacity() const;void setStackSize(int stackSize);int getStackSize() const;int used() const;int allocated() const;int available() const;void start(Runnable& target);void start(Runnable& target, const std::string& name);void startWithPriority(Thread::Priority priority, Runnable& target);void startWithPriority(Thread::Priority priority, Runnable& target, const std::string& name);void stopAll();void joinAll();void collect();const std::string& name() const;static ThreadPool& defaultPool();protected:PooledThread* getThread();PooledThread* createThread();void housekeep();private:ThreadPool(const ThreadPool& pool);ThreadPool& operator = (const ThreadPool& pool);typedef std::vector<PooledThread*> ThreadVec;std::string _name;int _minCapacity;int _maxCapacity;int _idleTime;int _serial;int _age;int _stackSize;ThreadVec _threads;mutable FastMutex _mutex;
};
从ThreadPool的定义看,它是一个PooledThread对象的容器。职责分成两部分:
第一,维护和管理池属性,如增加线程池线程数目,返回空闲线程数目,结束所有线程
第二,把需要运行的业务委托给PooledThread对象,通过接口start(Runnable& target)
void ThreadPool::start(Runnable& target)
{getThread()->start(Thread::PRIO_NORMAL, target);
}
函数getThread()为ThreadPool的私有函数,作用是获取一个空闲的PooledThread线程对象,实现如下
PooledThread* ThreadPool::getThread()
{FastMutex::ScopedLock lock(_mutex);if (++_age == 32)housekeep();PooledThread* pThread = 0;for (ThreadVec::iterator it = _threads.begin(); !pThread && it != _threads.end(); ++it){if ((*it)->idle()) pThread = *it;}if (!pThread){if (_threads.size() < _maxCapacity){pThread = createThread();try{pThread->start();_threads.push_back(pThread);}catch (...){delete pThread;throw;}}else throw NoThreadAvailableException();}pThread->activate();return pThread;
}
第二层中PooledThread对象为一个在线程池中线程。作为线程池中的线程,其创建于线程池的创建时,销毁于线程池的销毁,生命周期同线程池。在其存活的周期中,状态可分为running task和idle。running状态为正在运行业务任务,idle为线程为闲置状态。Poco中PooledThread继承自Runnable,并且包含一个Thread对象。
class PooledThread: public Runnable
{
public:PooledThread(const std::string& name, int stackSize = POCO_THREAD_STACK_SIZE);~PooledThread();void start();void start(Thread::Priority priority, Runnable& target);void start(Thread::Priority priority, Runnable& target, const std::string& name);bool idle();int idleTime();void join();void activate();void release();void run();private:volatile bool _idle;volatile std::time_t _idleTime;Runnable* _pTarget;std::string _name;Thread _thread;Event _targetReady;Event _targetCompleted;Event _started;FastMutex _mutex;
};
对于PooledThread来说,其线程业务就是不断的检测是否有新的外界业务_pTarget,如果有就运行,没有的话,把自己状态标志位限制,供线程池回收。
void PooledThread::run()
{_started.set();for (;;){_targetReady.wait();_mutex.lock();if (_pTarget) // a NULL target means kill yourself{_mutex.unlock();try{_pTarget->run();}catch (Exception& exc){ErrorHandler::handle(exc);}catch (std::exception& exc){ErrorHandler::handle(exc);}catch (...){ErrorHandler::handle();}FastMutex::ScopedLock lock(_mutex);_pTarget = 0;
#if defined(_WIN32_WCE)_idleTime = wceex_time(NULL);
#else_idleTime = time(NULL);
#endif _idle = true;_targetCompleted.set();ThreadLocalStorage::clear();_thread.setName(_name);_thread.setPriority(Thread::PRIO_NORMAL);}else{_mutex.unlock();break;}}
}
Poco中线程池的实现,耦合性其实是很低的,这不得不归功于其在线程池上两个层次的封装和抽象,类的内聚性非常强的,每个类各干各的事。
3.3 其他
除了上面线程池的主要属性和接口外,Poco中线程池还实现了一些其他特性。如设置线程运行的优先级,实现了一个默认线程的单件等。
(版权所有,转载时请注明作者和出处 http://blog.csdn.net/arau_sh/article/details/8592579)
转载于:https://www.cnblogs.com/napu/archive/2013/02/19/5375911.html
POCO C++库学习和分析 -- 线程 (二)相关推荐
- POCO C++库学习和分析
POCO C++库学习和分析 -- 序 1. POCO库概述: POCO是一个C++的开源库集.同一般的C++库相比,POCO的特点是提供了整一个应用框架.如果要做C++程序应用框架的快速开发,我觉得 ...
- POCO C++库学习和分析 -- 序
POCO C++库学习和分析 -- 序 1. POCO库概述: POCO是一个C++的开源库集.同一般的C++库相比,POCO的特点是提供了整一个应用框架.如果要做C++程序应用框架的快速开发,我觉得 ...
- POCO C++库学习和分析 -- 异常、错误处理、调试
POCO C++库学习和分析 -- 异常.错误处理.调试 1. 异常处理 C++同C语言相比,提供了异常机制.通过使用try,catch关键字可以捕获异常,这种机制使得程序员在程序异常发生时,可以通过 ...
- POCO C++库学习和分析 -- 字符编码
POCO C++库学习和分析 -- 字符编码 1. 字符编码 1.1 字符编码的概念 字符编码可以理解为在计算机上语言符号和二比特数之间的映射.不同的编码方式对应着不同映射方法,对于映射集的双方而言, ...
- poco,c++库学习,日期和时间
POCO C++库学习和分析 -- 日期与时间 在Poco库中,与时间和日期相关的一些类,其内部实现是非常简单的.看相关文档时,比较有意思的倒是历史上的不同时间表示法. 1. 系统时间函数 ...
- 26muduo_net库源码分析(二)
1.类图 2.Channel (1)Channel是selectable IO channel,负责注册与响应IO事件,它不拥有filedescriptor. (2)Channel是Acceptor. ...
- Golang 库学习笔记 Gin(二)
介绍 Gin 是一个用 Go (Golang) 编写的 web 框架. 它是一个类似于 martini 但拥有更好性能的 API 框架, 由于 http router,速度提高了近 40 倍. 如果你 ...
- 11muduo_base库源码分析(二)
1.为什么需要原子性操作 (1)x++; (2)从内存中读x的值到寄存器中,对寄存器加1,再把新值写回x所处的内存地址 2.gcc原子性操作 (1)原子自增操作 type __sync_fetch_a ...
- C++STL标准库学习总结/索引/学习建议
前言: 如果刚刚开始学习STL标准库,不知道从哪里入手学习的话,建议去中国大学mooc平台,先学习北京大学郭炜老师的<程序设计与算法(一)C语言程序设计>(https://www.icou ...
- Guava库学习:学习Guava EventBus(二)EventBus 事件订阅示例
2019独角兽企业重金招聘Python工程师标准>>> 原文地址:Guava库学习:学习Guava EventBus(二)EventBus 事件订阅示例 上一篇Guava库学习:学习 ...
最新文章
- 部署可扩展的目标检测管道:推理过程(上)
- 10个必会的 PyCharm 技巧
- Spark(四) -- Spark工作机制
- 百万数据报表导出:原理分析与总结
- php+node+redis,redis,nodejs,php,pub/sub 实战: 微信语音识别
- springboot-vue项目前台1
- this到底指向哪里
- Linux的sort命令
- junit进行单元测试_通过JUnit规则轻松进行AppEngine单元测试
- 如何手动修改XP系统属性中的技术支持信息
- matlab考试题烟台大学,徐骞-计算机控制与工程学院
- [Ext JS ][12.13] FieldSet 与 Grid结合 ,实现FieldSet 显示Gird中Store 的数量
- 猜51CTO的人群结构
- t-SNE可视化-Python实现
- 【论文笔记】BusTr,基于实时交通数据的公交旅行时间预测
- 电机噪音测试:手持式噪音计术语1
- 【MySQL 8.0 OCP 1Z0-908认证考试】 题库精讲--第二讲mysql主从
- Pytorch+PyG实现GraphConv
- 有两台计算机的IP地址分别为:192.168.1.100 和 192.168.2.10请问该采取什么样的办法让他们通信?
- Android项目小记——nomedia文件与MediaStore媒体库