C++实现线程池

c++实现线程池

本文将不会使用C++不易理解的特性,将使用最基本的c++语法实现一个线程对象以及线程池,
完整工程见:https://github.com/wk-xjd/wkthreadpool

自旋锁类

#ifndef WKLOCKER_H
#define WKLOCKER_H
#include <mutex>
#include <atomic>
#include <condition_variable>

class WKLocker
{
public:
	WKLocker(int spinTimes = 20);
	~WKLocker();
	
	void lock();
	void unlock();

private:
	std::atomic<unsigned int> m_currentThreadId = 0;
	std::condition_variable m_condition;
	int m_lockCount = 0;
	std::mutex m_muetex;
	unsigned int m_exceptValue = 0;
	int m_spinCount;
	std::atomic<bool> m_delete = false;
};

#endif
#include "WKLocker.h"
#include "utils.h"

WKLocker::WKLocker(int spinTimes)
	: m_spinCount(spinTimes)
{

}
WKLocker::~WKLocker()
{
	m_delete = true;
	m_condition.notify_all();
}

void WKLocker::lock()
{
	unsigned int curThrId = WKUtils::currentThreadId();
START_GET_LOCK:
	{
		//自旋
		std::atomic<int> currCount = m_spinCount;
		while (!m_currentThreadId.compare_exchange_weak(m_exceptValue, curThrId))
		{
			if (!currCount.fetch_sub(1))
				break;
		}
		//自旋失败获取锁失败则阻塞
		if (m_currentThreadId == curThrId)
		{
			m_lockCount++;	//重入
		}
		else
		{
			std::unique_lock<std::mutex> locker(m_muetex);
			m_condition.wait(locker, [&]()
				{return m_currentThreadId == m_exceptValue; });
			locker.unlock();
			//锁被让出后,重新获取锁
			if (!m_delete)
				goto START_GET_LOCK;
		}
	}
}

void WKLocker::unlock()
{
	unsigned int curThrId = WKUtils::currentThreadId();

	if (m_currentThreadId == curThrId)
	{
		if (!(--m_lockCount))
		{
			//锁释放后唤醒所有阻塞在该锁的线程
			m_currentThreadId = m_exceptValue;
			m_condition.notify_all();
			m_lockCount = 0;
		}
	}
}

线程任务类

通过添加任务的方式启动在新线程中执行,则需要继承该线程任务类
#ifndef WKTHREAGTASK_H
#define WKTHREAGTASK_H

/*
	线程任务基类(抽象类)
	1.任务入口:重写纯虚函数run函数,
	2.任务结束回调入口:重写虚函数callback函数
	3.任务有三个优先级(PriortyLevel),默认为LOW,将任务添加到线程池任务队列时,会优先处理高优先级任务
	4.getTaskId(虚函数可重写),默认使用实例对象的地址的hashcode
	5.可以设置m_autoDelete属性,任务执行结束后是否自动释放该对象,若为ture,一定要重写析构函数
*/
class WKThreadTask
{
public:
	enum PriortyLevel
	{
		Low,
		Middle,
		Hight,
	};
	WKThreadTask() {};
	virtual ~WKThreadTask() {};
	virtual void run() = 0;
	virtual void callback() {};
	virtual unsigned int getTaskId() { return hash_task_fn(this); }
	PriortyLevel taskPriorty() { return m_priorty; }
	void setTaskPriorty(PriortyLevel level) { m_priorty = level; }
	bool isAutoDelete() { return m_autoDelete; } const
	void setAutoDelete(const bool isAutoDeleted = false) { m_autoDelete = isAutoDeleted; }
private:
	std::hash<WKThreadTask*> hash_task_fn;
	unsigned int m_taskId = 0;
	PriortyLevel m_priorty = PriortyLevel::Low;
	bool m_autoDelete = false;
};

#endif //WKTHREAGTASK_H

线程类

#pragma once
#ifndef WKThread_H
#define WKThread_H

#include <thread>
#include <atomic>
#include <mutex>   
#include <deque>
#include <condition_variable>
#include "WKLocker.h"

class WKThreadTask;

/*
	WKThread线程类使用方式:
	1.继承WKThread类,并重写run方法,
		通过start方法启动线程并执行,线程执行完毕自动释放该线程
	2.实例化WKThread对象,并将继承了WKThreadTask的线程任务添加到线程,
		2.1 通过start方法启动线程,
		2.2 线程任务执行完毕后,线程不会立即释放,
		2.3 线程任务执行完毕后进入挂起状态,等待下一次添加任务唤醒
		2.4 线程随实例化对象释放而释放,也可以通过quit方法释放线程
*/
class WKThread
{
public:
	enum ThreadState
	{
		Running,
		Finished,
		Waiting,
	};
	WKThread();
	virtual ~WKThread();
	void start();	//启动线程
	void quit();	//退出线程
	void wake();	//唤醒线程
	void wait();	//挂起线程
	bool addTask(WKThreadTask* task);	//添加线程任务,并唤醒线程,返回任务是否添加成功
	void setNextTaskQueue(std::deque<WKThreadTask*>* nextTaskQueue);	//传递一个任务队列,当前线程任务执行完毕后自动从任务队列中取任务
	void removeNextTaskQueue();	//移除任务队列
	const bool hasNextTaskQueue();	//是否有任务队列

	WKThread* getInstance();	//获取当前线程对象地址
	unsigned int getThreadId() const;	//获取线程id

	bool isRunning() const;	//当前线程是否正在运行
	bool isFinished() const;	//线程任务是否执行完成
	bool isWaiting() const;	//线程是否处于挂起等待状态

protected:
	virtual void run();	//线程执行(用户)任务入口,若该方法未被重写使用方式2创建线程任务,否则使用方式1

private:
	void _runTask();	//通过std库获取到的线程入口
	void _updateState(ThreadState state);	//更新线程状态

private:
	std::thread* m_stdThread = nullptr; 
	std::atomic<bool> m_bWaitFlag = false;
	std::atomic<bool> m_bQuitFlag = true;
	std::atomic<enum ThreadState> m_state = ThreadState::Waiting;
	std::mutex m_mutex;
	std::condition_variable m_condition;
	unsigned int m_threadId = 0;
	WKThreadTask* m_task = nullptr;
	WKLocker m_wkLocker;	//状态锁
	WKLocker m_nextQueueWKLocker;	//队列锁
	std::deque<WKThreadTask*>* m_nextTaskQueue = nullptr;
};
#endif // WKThread_H

线程池类

#include <queue>
#include <thread>
#include <atomic>
#include <deque>
#include <mutex>
#include <condition_variable>
#include "WKLocker.h"

class WKThread;
class WKThreadTask;
/*
	线程池
	1.懒创建线程,有任务且线程数小于最大线程数时创建新的线程
	2.动态调整轮询检查线程状态的间隔
*/
class WKThreadPool
{
public:
	WKThreadPool();	
	WKThreadPool(int maxThreadSize, int maxTaskSize);
	~WKThreadPool();
	void start();	//启动线程池
	void stop();	//停止线程池,停止加入任务
	bool isStop() const;	//线程池是否被终止
	bool addTask(WKThreadTask* task);	//添加任务,返回任务添加结果
	int waitThreadCount() const; 	//挂起等待线程数
	int doneThreadCount() const; 	//运行工作线程数
	int maxThreadSize() const;	//最大线程数
	int maxTaskSize() const;	//最大任务队列最大任务数
	int currentTaskSize() const; 	//当前任务数

private:
	void _benginScheduler();	//调度管理
	void _createThread();	//创建一个新的线程
	void _checkThreadQueue();	//检查线程运行情况,将空闲线程置于空闲线程队列中
	void _stopAllThread();	//停止加入新任务,执行完队列中的任务
	void _sleepIntrval(const int ms);	//调度间隔
	WKThreadTask* _getTask();	//取一个队首任务
	void _updateElasticInterval(); // 更新弹性的检查间隔,工作线程增多则间隔检查间隔减少,否则增加
	
private:
	std::thread* m_pollingThread = nullptr;
	std::deque<WKThreadTask*> m_taskQueue;
	std::queue<WKThread*> m_threadDoneQueue;
	std::queue<WKThread*> m_threadWaitQueue;
	std::atomic<bool> m_bStoped = true;
	std::atomic<int> m_threadDoneCount = 0;
	std::atomic<int> m_threadWaitCount = 0;
	std::atomic<int> m_taskCount = 0;
	int m_maxThreadSize = 0;
	int m_maxTaskSize = 30;
	std::atomic<bool> m_bExiting = false;
	std::condition_variable m_condition;
	std::mutex m_mutex;
	int m_lastWaitThreadcount = 0;
	int m_waitThreadCountGradient = 0;
	int m_sleepIntrval = 0;
	WKLocker m_threadQueueWKLocker;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 实现线程池的方法有很多,但是最常见的方法是使用队列来维护任务。每个线程都在队列中等待任务,当有新任务到达时,就从队列中取出一个任务并执行。这样,每个线程都可以在并行执行任务,而不需要创建新的线程。 在C语言中实现线程池的代码如下: ``` #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 5 void *print_hello(void *threadid) { long tid; tid = (long)threadid; printf("Hello World! It's me, thread #%ld!\n", tid); pthread_exit(NULL); } int main(int argc, char *argv[]) { pthread_t threads[NUM_THREADS]; int rc; long t; for (t = 0; t < NUM_THREADS; t++) { printf("In main: creating thread %ld\n", t); rc = pthread_create(&threads[t], NULL, print_hello, (void *)t); if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } pthread_exit(NULL); } ``` ### 回答2: 要实现线程池,首先需要先了解线程池的基本概念和原理。 线程池是一种用来管理和复用线程的技术,它能够维护一个线程队列,按需创建和销毁线程,并将任务分配给这些线程来执行。使用线程池可以提高程序的性能,减少线程创建和销毁的开销。 在C语言中,可以使用多线程的库来实现线程池,比如pthread库。下面是一个简单的用C语言实现线程池的步骤: 1. 定义线程池结构体:创建一个结构体来保存线程池的相关信息,如线程池的大小、任务队列、互斥、条件变量等。 2. 初始化线程池:在初始化函数中,需要对线程池中的各个成员进行初始化,如创建指定数量的线程、初始化互斥和条件变量等。 3. 定义任务函数:线程池的任务函数用于处理任务队列中的任务,根据具体需求来定义任务的执行逻辑。 4. 添加任务到线程池:当有新的任务时,将任务添加到任务队列中,并通过条件变量来通知线程池中的线程有新任务可执行。 5. 线程池中的线程获取任务并执行:在线程中循环检查任务队列,当有任务时,线程从任务队列中获取任务并执行。 6. 销毁线程池:在停止使用线程池时,要销毁线程池中的资源,包括线程的回收、互斥和条件变量的销毁等。 通过以上步骤,就可以在C语言中实现一个简单的线程池。具体实现中还需要考虑线程同步、任务队列的管理等问题,以确保线程池的稳定性和性能。 ### 回答3: 线程池是用来管理和复用线程的一种机制,可以更有效地使用系统资源和提高应用程序的性能。下面是使用C语言实现线程池的一般步骤: 1. 定义一个线程池的结构体,包含线程池的状态、大小、最大线程数、工作任务队列等信息。 ```c typedef struct { pthread_t *threads; // 线程数组 int thread_count; // 线程数 int max_threads; // 最大线程数 int pool_size; // 线程池大小 int shutdown; // 关闭标志 pthread_mutex_t mutex; // 互斥 pthread_cond_t notify; // 条件变量 Task *task_queue; // 任务队列 } ThreadPool; ``` 2. 初始化线程池,创建指定数量的线程。 ```c ThreadPool* thread_pool_init(int pool_size) { ThreadPool *pool = malloc(sizeof(ThreadPool)); pool->threads = malloc(pool_size * sizeof(pthread_t)); pool->thread_count = pool_size; pool->max_threads = pool_size; pool->pool_size = 0; pool->shutdown = 0; // 初始化互斥和条件变量 pthread_mutex_init(&(pool->mutex), NULL); pthread_cond_init(&(pool->notify), NULL); // 创建线程 for (int i = 0; i < pool_size; i++) { pthread_create(&(pool->threads[i]), NULL, thread_worker, (void*)pool); } return pool; } ``` 3. 定义线程工作函数,不断从任务队列中取出任务执行。 ```c void* thread_worker(void *arg) { ThreadPool *pool = (ThreadPool*)arg; while (1) { pthread_mutex_lock(&(pool->mutex)); // 线程池关闭,退出线程 while (pool->pool_size == 0 && !pool->shutdown) { pthread_cond_wait(&(pool->notify), &(pool->mutex)); } if (pool->shutdown) { pthread_mutex_unlock(&(pool->mutex)); pthread_exit(NULL); } // 从任务队列中取出任务执行 Task *task = pool->task_queue; pool->task_queue = pool->task_queue->next; pool->pool_size--; pthread_mutex_unlock(&(pool->mutex)); task->func(task->arg); free(task); } pthread_exit(NULL); } ``` 4. 定义任务结构体,包含任务函数指针和参数。 ```c typedef struct Task { void (*func)(void*); void *arg; struct Task *next; } Task; ``` 5. 向线程池中添加任务。 ```c void thread_pool_add_task(ThreadPool *pool, void (*func)(void*), void *arg) { Task *task = malloc(sizeof(Task)); task->func = func; task->arg = arg; task->next = NULL; pthread_mutex_lock(&(pool->mutex)); if (pool->task_queue == NULL) { pool->task_queue = task; } else { Task *cur = pool->task_queue; while (cur->next != NULL) { cur = cur->next; } cur->next = task; } pool->pool_size++; pthread_mutex_unlock(&(pool->mutex)); pthread_cond_signal(&(pool->notify)); } ``` 6. 关闭线程池。 ```c void thread_pool_shutdown(ThreadPool *pool) { if (pool == NULL) { return; } pthread_mutex_lock(&(pool->mutex)); pool->shutdown = 1; pthread_mutex_unlock(&(pool->mutex)); pthread_cond_broadcast(&(pool->notify)); // 等待线程退出 for (int i = 0; i < pool->thread_count; i++) { pthread_join(pool->threads[i], NULL); } // 释放资源 free(pool->threads); while (pool->task_queue != NULL) { Task *next = pool->task_queue->next; free(pool->task_queue); pool->task_queue = next; } pthread_mutex_destroy(&(pool->mutex)); pthread_cond_destroy(&(pool->notify)); free(pool); } ``` 以上是一个简单的线程池实现,通过初始化线程池、添加任务、关闭线程池等操作,可以有效地管理和复用线程,提高应用程序的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值