(1)简单线程池的实现,如何保证线程池是线程安全的?
首先给大家普及下线程池的知识。我写的线程池是使用POSIX写的。线程池整个项目中包括两个类:一个是Task类,用于描述执行一个任务的方法(一个函数)和执行这个任务所需要的参数(函数的参数)。另外一个类就是我们的线程池类ThreadPool类,在线程池中主要有两个队列,一个是Task类队列,用于存放要处理的任务。一个是线程池中存放线程的数组。下面我就面试官的问题给出回答:
在线程池类中通过一个互斥锁(pthread_mutex_t类型变量)来实现线程池的线程安全性。每次往任务队列中添加任务、或者从任务队列中取任务前都要使用pthread_mutex_lock函数加一把锁,然后对任务队列进行操作。操作完后再使用pthread_mutex_unlock释放这个锁,从而实现对任务队列的互斥访问。也就是说每次想要对任务队列进行操作都需要:
pthread_mutex_lock(&mutex);
增加任务到任务队列或者从任务队列取任务;
pthread_mutex_unlock(&mutex);
来互斥的访问任务队列。以避免多个线程同时操作任务队列造成死锁。如任务队列只剩下一个空位置,但是多个线程同时向任务队列中添加任务;任务队列中只剩下一个任务,但是多个线程同时到任务队列中取任务;使用互斥锁来实现线程安全的访问任务队列。
(2)当有一个任务进入任务队列时,其他阻塞线程是如何获取并执行这个任务的?
前面我们说过,在ThreadPool的构造函数中根据我们指定的个数使用new来动态创建线程数组。然后使用pthread_create为每个线程注册线程启动函数,在线程启动函数中每一个前程启动函数都要对任务队列进行实时监控,使得一旦有任务到来我们的空闲线程就去任务队列获取并执行任务,每个线程函数都是互斥的访问任务队列。
由于刚开始时没有任务到来,我们可以在线程函数中使用条件变量(pthread_cond_t)使得的线程都处于阻塞状态phtread_cond_wait(&cond, &mutex)。一旦有任务到来就使用pthread_cond_signal(&cond)来激活一个因为该条件而阻塞的线程。当然也可以使用pthread_cond_broadcast(&cond)
线程函数中的代码架构如下
void * threadFunc(void *paramter)//线程中的线程启动函数,相当于执行任务的函数
{
...
pthread_mutex_lock(&mutex);//加锁对任务队列互斥访问
while(任务队列为空)
{
pthread_cond_wait(&cond, &mutex);
}
....//获取任务
pthread_mutex_unlock(&mutex);
....//执行任务
}
注意:1)这里我们首先使用了pthread_mutex_lock对任务队列加锁实现多个线程互斥访问任务队列。
2)判断任务队列为空时,使用的是while循环而不是if,这里可以防止出现“虚假唤醒”的情况。
3)当程序执行到pthread_cond_wait函数内部时,首先会释放掉互斥锁,线程函数阻塞到这里,不再往下运行。当有任务时会以“信号”的形式唤醒该线程函数,加锁并继续往下执行。所以pthread_cond_wait函数=pthread_mutex_unlock+pthread_mutex_lock这两个函数功能。
向任务队列中添加任务的代码架构如下:
void addTast()
{
pthread_mutex_lock(&mutex);//因为要互斥的访问任务队列,加锁
....//将任务添加到任务队列
pthread_cond_signal(&cond);或者是pthread_cond_broadcast(&cond);//发送信号给一个因为该条件而阻塞的线程
pthread_mutex_unlock(&mutex);//解锁
}
————————————————
原文链接:https://blog.csdn.net/bian_qing_quan11/article/details/73333214