http项目——动态线程池的模拟实现

本文详细介绍了如何设计并实现一个动态线程池,包括线程池的扩容与缩容策略,通过调整线程数量以提高资源利用率,确保系统的高效运行。

在这里插入图片描述
       之前写http服务器的时候,用到了线程池去完成服务器的创建,之前的线程池实现参照:https://blog.youkuaiyun.com/tonglin12138/article/details/94035217。

       但是之前给出的实现有一个最大的缺陷就在于线程数量一开始就是给死的。我们在线程池初始化的时候直接一次性的创建了一批线程。其实更加完善的做法应该是模拟实现一个动态的线程池出来:当当前处于工作状态的线程数量与创建的线程数量一样的时候,我们应该再创建一些线程;当处于休眠状态线程的数量大于我们设置的最大线程休眠数量的时候,我们应该回收一部分线程。从而达到实现出一个动态的线程池的目的。

1.动态线程池的实现思想

1.之前的线程池类的私有成员作出改变
class ThreadPool
{
private:
//int thread_total_num;
int thread_free_num; //最大休眠线程数
queue< Task > task_queue;
pthread_t *thread_id;
int thread_max_num; //线程池容纳最大线程数
int thread_cur_num; //当前线程池存放的线程数
int thread_cur_task_num //当前工作的线程数
pthread_mutex_t lock;
pthread_cond_t cond;
bool isquit;
};

2.扩容:在向任务队列中push任务之后,进行判断:

if ((thread_cur_task_num  == thread_cur_num) && 
(thread_cur_num < thread_max_num)){

			//扩容
tp->threadid = (pthread_t *)realloc(tp->threadid, 
(thread_cur_num + 1) * sizeof (pthread_t));     /**< 新增线程 */

pthread_create(&(tp->threadid[current_pthread_num]),
 NULL, ThreadPoolRoutine, (void*)pool);

tp->thread_cur_num++;    /**< 当前池中线程总数加1 */

		}

我们这里的扩容有用到realloc函数。在之前malloc出来的thread_id的空间大小上进行扩容,新的地址空间作为pthread_create()函数的第一个参数。

3.缩容:在线程从任务队列取出任务执行之后进行判断:

	
if ((tp->thread_cur_num - tp->thread_cur_tasknum) 
                           > tp->thread_free_num)
			{
                  //缩容			

				thread_cur_num--;
				break;
			}

因为每个线程执行前的一件事我们都进行了pthread_detach(),所以直接break,线程就会自动回收。

2.动态线程池的实现代码

#ifndef __THREAD_POOL_HPP__
#define __THREAD_POLL_HPP__
/*线程池
*1.线程池中有五个线程
*2.利用条件变量
*3.在队列总添加任务
*  queue<Task> task_queue
*4.加锁
*   pthread_mutex_t lock
*5.唤醒
*   pthread_cond_t cond
*6.任务类
*
*/
#include<iostream>
#include<pthread.h>
#include<queue>
#include<sys/time.h>
#include<unistd.h>
#define NUM 5
#include"Log.hpp"
using namespace std;

typedef int(*handler_t) (int);

//任务结构
class Task
{
private:
	int sock_;
	handler_t handler_;
public:
	Task()
	{
		sock_ = -1;
		handler_ = NULL;
	}
	void SetTask(int sock, handler_t handler)
	{
		sock_ = sock;
		handler_ = handler;
	}
	void Run()
	{
		handler_(sock_);
	}

	~Task()
	{}
};

//线程池
class ThreadPool
{
private:
	//int thread_total_num;
	int thread_free_num;   //最大休眠线程数
	queue<Task> task_queue;
	
	pthread_t *thread_id;
	int thread_max_num;   //线程池容纳最大线程数
	int thread_cur_num;   //当前线程池存放的线程数
	int thread_cur_task_num  //当前工作的线程数
	
	pthread_mutex_t lock;
	pthread_cond_t cond;
	bool isquit;
private:
	void LockQueue()
	{
		pthread_mutex_lock(&lock);
	}

	void UnLockQueue()
	{
		pthread_mutex_unlock(&lock);
	}

	void GetTask(Task & t)
	{
		t = task_queue.front();
		task_queue.pop();
	}
	bool IsEmpty()
	{

		if (task_queue.size() == 0)
			return true;
		return false;

	}

	void ThreadWait()
	{
		//如果线程池退出了则线程退出
		if (isquit)
		{
			//退出前解锁
			UnLockQueue();
			thread_total_num--;
			pthread_exit((void*)0);
		}
		pthread_cond_wait(&cond, &lock);
		thread_idle_num++;
	}

	void WeakUpThread()
	{
		pthread_cond_signal(&cond);
		thread_idle_num--;
	}
	void WeakUpAllThread()
	{

		pthread_cond_broadcast(&cond);
	}

	//如果不是static会有this指针
	static void* Thread_Routine(void* arg)
	{
		//分离线程
		ThreadPool* tp = (ThreadPool*)arg;
		pthread_detach(pthread_self());
		while (1)
		{
			tp->LockQueue();
			while (tp->IsEmpty())
			{
				//等待
				tp->ThreadWait();
			}

		


			//取任务
			Task t;
			tp->GetTask(t);
			tp->thread_cur_task_num++;
			//解锁
			tp->UnLockQueue();
			//处理任务
			t.Run();
	

			if ((tp->thread_cur_num - tp->thread_cur_tasknum) > tp->thread_free_num)
			{
                  //缩容			

				thread_cur_num--;
				break;
			}


		}
	}
public:
	ThreadPool(int n1 =20 , int n2 = 2) :thread_max_num(n1), thread_free_num(n2), thread_cur_task_num(0)
	{
		pthread_mutex_init(&lock, NULL);
		pthread_cond_init(&cond, NULL);
	}

	void InitThreadPool()
	{
		int i = 0;
		//pthread_t id[NUM];
		thread_id = (pthread_t *)malloc(NUM*sizeof(pthread_t));


		for (i; i < NUM; i++)
		{
			pthread_create(&thread_id[i], NULL, Thread_Routine, this);
			thread_cur_num++;
		}

		LOG(INFO, "create thread");
	}



	void PushTask(Task& t)
	{
		//加锁
		LockQueue();
		//如果是需要退出了则不能在继续添加线程
		if (isquit)
		{
			UnLockQueue();
			return;
		}

		if ((thread_cur_task_num  == thread_cur_num) && (thread_cur_num < thread_max_num)){

			//扩容
			tp->threadid = (pthread_t *)realloc(tp->threadid, (current_pthread_num + 1) * sizeof (pthread_t));     /**< 新增线程 */
			pthread_create(&(tp->threadid[current_pthread_num]), NULL, ThreadPoolRoutine, (void*)pool);
			pool->current_pthread_num++;    /**< 当前池中线程总数加1 */

		}

		//添加任务
		task_queue.push(t);
		//唤醒线程
		WeakUpThread();
		//解锁
		UnLockQueue();
	}

	void StopThread()
	{
		//加锁
		LockQueue();
		//isqueue设置为true
		isquit = true;
		//解锁
		UnLockQueue();
		if (thread_idle_num > 0)
		{
			WeakUpAllThread();
		}

	}

	~ThreadPool()
	{
		pthread_mutex_destroy(&lock);
		pthread_cond_destroy(&cond);
	}
};

#endif

具体的实现与之前的代码其实差别不是太大,代码里边有的变量名字可能需要订正,并不影响解读。

### 动态线程池框架的实现方案 #### Java中的动态线程池实现 在Java中,可以通过继承`ThreadPoolExecutor`类并重写其提供的钩子方法来实现动态线程池的功能。例如,`beforeExecute`、`afterExecute` 和 `terminated` 方法允许开发者在线程执行前后以及线程池终止时插入自定义逻辑[^2]。此外,还可以通过动态调整核心线程数 (`corePoolSize`) 和最大线程数 (`maximumPoolSize`) 来适应不同的负载情况。 以下是基于Java的一个简单动态线程池实现示例: ```java import java.util.concurrent.*; public class DynamicThreadPool extends ThreadPoolExecutor { public DynamicThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override protected void beforeExecute(Thread t, Runnable r) { System.out.println("Thread " + t.getName() + " is about to execute task."); // 可在此处记录任务启动时间或其他元数据 } @Override protected void afterExecute(Runnable r, Throwable t) { if (t != null) { System.err.println("Task execution failed with exception: " + t.getMessage()); } System.out.println("Task executed by thread " + Thread.currentThread().getName()); // 记录任务完成时间和耗时等信息 } @Override protected void terminated() { System.out.println("ThreadPool has been shut down."); // 执行清理工作或通知其他组件 } public static void main(String[] args) throws InterruptedException { DynamicThreadPool pool = new DynamicThreadPool(2, 4, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); for (int i = 0; i < 5; i++) { final int taskId = i; pool.submit(() -> { try { System.out.println("Executing Task " + taskId); Thread.sleep(1000); // Simulate some workload } catch (InterruptedException e) { throw new RuntimeException(e); } }); } pool.shutdown(); pool.awaitTermination(1, TimeUnit.MINUTES); } } ``` 上述代码展示了如何创建一个支持动态行为的线程池,并利用钩子函数实现了任务执行前后的日志记录功能。 --- #### Python中的动态线程池实现 Python 中可以借助标准库模块 `concurrent.futures.ThreadPoolExecutor` 或第三方库如 `billiard`(Celery 的底层依赖之一)来构建动态线程池。虽然原生的 `ThreadPoolExecutor` 不提供直接的方法用于修改运行参数,但可以通过封装的方式间接实现动态特性。 下面是一个简单的例子展示如何使用 `concurrency.futures` 构建基础线程池,并结合外部控制机制模拟动态调整能力: ```python from concurrent.futures import ThreadPoolExecutor, as_completed import time class DynamicThreadPool: def __init__(self, max_workers=4): self.executor = ThreadPoolExecutor(max_workers=max_workers) def submit_task(self, func, *args, **kwargs): future = self.executor.submit(func, *args, **kwargs) return future def shutdown(self, wait=True): self.executor.shutdown(wait=wait) def worker(task_id): print(f"Starting Task {task_id}") time.sleep(1) # Simulating a delay print(f"Finished Task {task_id}") return f"Result of Task {task_id}" if __name__ == "__main__": dynamic_pool = DynamicThreadPool(max_workers=3) futures = [] for i in range(5): futures.append(dynamic_pool.submit_task(worker, i)) for fut in as_completed(futures): print(fut.result()) dynamic_pool.shutdown() ``` 此脚本演示了一个基本的任务提交流程,其中可以根据需要重新初始化具有不同配置的新线程池实例以达到动态效果。 --- #### C++中的动态线程池实现 C++ 并未像 Java 那样内置高级并发工具集;然而,借助 STL 提供的标准容器与多线程支持(std::thread),同样能设计出高效的线程池解决方案。为了使它具备动态属性,则需引入额外的状态管理结构以便实时更新资源分配策略。 这里给出一段简化版的 C++ 线程池模板代码片段作为参考: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> #include <future> #include <mutex> #include <condition_variable> class ThreadPool { private: std::vector<std::thread> workers; std::queue<std::function<void()>> tasks; mutable std::mutex queue_mutex; std::condition_variable condition; bool stop; public: explicit ThreadPool(size_t threads): stop(false){ for(auto i = 0u ;i <threads;++i){ workers.emplace_back([this]{ this->worker_loop();}); } } ~ThreadPool(){ { std::unique_lock<std::mutex> lock(queue_mutex); stop=true; } condition.notify_all(); for(std::thread &worker :workers){ if(worker.joinable()){ worker.join(); } } } template<class F,class...Args> auto enqueue(F&&f, Args&&...args)->std::future<decltype(f(args...))>{ using return_type=decltype(f(args...)); auto task_func=[f,std::forward_as_tuple(args...) ]()->return_type{ return std::apply(f,std::move(forwarded_args)); }; std::packaged_task<return_type()> task(std::move(task_func)); std::future<return_type> res=task.get_future(); { std::lock_guard<std::mutex> lock(queue_mutex); if(stop){ throw std::runtime_error("enqueue on stopped ThreadPool"); } tasks.emplace([&task](){task();}); } condition.notify_one(); return res; } private: void worker_loop(){ while(true){ std::function<void()> task; { std::unique_lock<std::mutex> lock(queue_mutex); condition.wait(lock,[this]{return stop || !tasks.empty();}); if(stop && tasks.empty()) break; task=std::move(tasks.front()); tasks.pop(); } task(); } } }; // Example usage void example_function(int id){ /* ... */} int main(){ ThreadPool pool(4); for(int i=0;i<8;i++){ pool.enqueue(example_function,i); } return 0; } ``` 该版本提供了灵活的任务队列管理和线程生命周期控制手段[^4]。 --- ### 总结 无论是采用哪种编程语言,动态线程池的核心理念均围绕着对现有计算资源的有效调度展开讨论。每种技术栈都有各自的优势领域——对于强类型静态编译的语言来说可能更注重性能调优层面的工作;而对于解释型或者半编译型语言而言则倾向于便捷性和快速迭代方面考虑更多因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拥抱@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值