基于线程池的生产者消费者模型(含阻塞队列)

本文介绍了线程池的概念和作用,以及如何在C++中实现一个简单的线程池模型。主要内容包括线程池的创建、任务的推送与获取、线程执行函数的设计。在模型实现部分,详细阐述了线程的创建、PushTask和PopTask函数的实现,以及线程执行函数Routines的编写。最后,给出了模型的测试方法,展示了一个主线程作为生产者不断向任务队列添加任务的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、线程池

二、模型实现

1、准备工作

2、创建线程

3、PushTask函数

4、PopTask函数

5、线程执行函数Routines

三、模型测试


一、线程池

和内存池一样,线程池也是为了提升效率。一个服务器可能短时间会接收到很多请求,等接收到请求再创建线程,此时就需要先创建线程,这样就会降低处理速度。

为了应对这种情况,我们一般会提前创建好一批线程,降低了短时间内创建和销毁线程的成本。就好比你要去火锅店吃火锅,店家不会等你来了再去屠宰场取肉,肯定会先把肉准备好。

二、模型实现

现在我们要建立这样一个模型,主线程作为生产者不断的向任务队列中添加任务,而线程池中的线程在不断从任务队列中拿任务。假设任务队列的容量是没有上限的。

和阻塞队列一样,要实现这么一个模型的关键依然是 放任务PushTask 和 取任务PopTask,除此之外,在创建线程的时候,有一个需要注意的细节

1、准备工作

2、创建线程

我们一次创建 4个线程,要传递给线程的参数暂定,为了方便,我们这里不主动回收线程,而是选择将线程分离。

 这里需要注意的是,pthread_create函数的第三个参数,传入的函数必须满足

(1) 返回值是 void*

(2) 输入的参数只有一个,那就是void*

但是实际上,Routines是定义在类中的,是一个成员函数,参数会包含一个隐藏的this指针,所以站在编译器的角度就变成了 Routines(ThreadPool<T>* this , void* args),所以我们在函数的最开始加上 static

成员函数一般都是放在代码区,成员函数加了static以后,此时会被放到全局区,这个时候参数就只有void*,不会包含隐藏的this指针 

3、PushTask函数

此时因为任务队列的容量没有上限,所以我们这里无需考虑任务队列为满的情况。_task_queue是临界资源,我们需要使用互斥锁来保护这个临界资源

互斥锁的初始化和销毁这里就不展示了。

还有一步我们需要等实现 PopTask函数以后再写

4、PopTask函数

取任务的时候,既要考虑到维护临界资源,又要考虑到任务队列为空的情况。

(1) 既然是维护临界资源,那就需要加锁和解锁

(2) 既然是考虑到任务队列是否为空,当任务队列为空的时候,说明消费者线程不能再继续取任务了,此时要把消费者线程加入到 条件变量中等待,当生产者线程加入任务时,再唤醒消费者线程。

条件变量的初始化和销毁,这里就不展示了。

 PopTask函数具体实现如下:

PushTask函数的补充:

5、线程执行函数Routines

现在Routines被放到了全局区,但是线程池中的线程需要访问 任务队列,因此我们需要给线程执行函数传递 this指针,这样的话,每个线程就可以访问到类成员变量了

 然后我们在线程执行函数中获得this指针,用一个名为that的指针来接收这个this指针

 我们可以写一个空的Task类,就像下面这样

 线程执行函数的完整代码如下:

 

三、模型测试

测试的主函数如下,主线程作为生产者线程每隔1s向任务队列添加任务。

 这里表现出来的效果和之前的阻塞队列差不多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值