POCO C++库学习和分析 -- 线程 (二)
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);
- }
- 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中线程池的实现,耦合性其实是很低的,这不得不归功于其在线程池上两个层次的封装和抽象,类的内聚性非常强的,每个类各干各的事。