使用线程池要小心,一不小心就会导致程序挂死。举例说明这种情况。
线程池中有一个同步队列存放数据,多个线程取队列中的数据去处理,数据的类型可能有多个,所以每种数据类型对应一个处理函数,假设某种数据的处理函数会把线程阻死,这时就悲剧了,这个阻死会蔓延到线程池的所有线程,最后线程池中所有的线程都挂死了,程序也挂死了。因为线程池的线程是不停的切换去处理数据的,凡是遇到会挂死线程的数据时,线程会一个个死掉,直到所有的线程挂死。
解决办法是:
一、一个类型的数据一个线程或者多个类型的数据一个线程,这样某个类型的数据处理导致线程挂死,其它线程还能正常运行,不会导致程序挂死。
二、线程池中加超时处理,超时处理就不会挂死线程。
使用线程池一定要保证线程处理函数不会挂死,否则整个程序都会挂死了。线程池内部的线程函数需要加超时处理,一个简单的处理方法是通过一个临时线程去控制该函数是否超时。原来的处理逻辑
while (m_running)
{
Task task; m_queue.Take(task); if (task) { task() } } 改成带超时的处理逻辑 while (m_running) { Task task; m_queue.Take(task); if (task) { boost::thread thd(task); if(thd.timed_join(boost::posix_time::seconds(5)))
{ cout<<"没有超时"<<endl;
} else
{
cout<<"超时"<<endl;
//要做超时处理,这时要释放导致超时的资源,比如关闭socket或者关闭数据库
//通知应用层做相应的处理如CloseSocket(),CloseDB()
} } }
超时处理时要把导致线程函数挂死的资源释放,比如关闭socket或者关闭数据库,让挂死的线程能退出。
注意:这里只是一个程序的容错保证,并不解决根本问题,解决根本问题还是要把导致线程卡死的函数的bug解决。
以上是关于线程池的陷阱的主要内容,如果未能解决你的问题,请参考以下文章
newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段