linux C thread pool two basic functions to achieve the basic Silu Jia

Thread pool is based on a producer-consumer model

 Which can be divided into the task queue, the thread pool, thread management of three parts

Task queue is a queue, the queue element is inside a structure, the structure put a function pointer and function parameters. In the critical area of ​​public variables, when accessed by different threads for thread synchronization, you need to lock handle.

There is a thread pool thread pid array structure, a thread pool began to have an initial number of threads and a maximum number of threads.

According to the task queue thread management information, to create a management thread pool.

// 任务结构体
typedef struct {
	void* (*function)(void*);      // 函数指针, 回调函数
	void* arg;                      // 上面函数的参数
}threadpool_task_t;


// 描述线程池相关信息
struct threadpool_t {
	pthread_mutex_t lock;           // 用于锁住本结构体
	pthread_mutex_t thread_counter; // 记录忙碌状态线程个数的锁
	pthread_cond_t queue_not_full;  // 当任务队列满时, 添加任务的线程阻塞,等待条件变量
	pthread_cond_t queue_not_empty; // 任务队列里不为空时,通知等待任务的线程

	pthread_t *threads;             // 存放线程池中每个线程的tip,数组
	pthread_t adjust_tid;           // 存放管理线程的tid
	threadpool_task_t* task_queue;  // 任务队列

	int min_thr_num;                // 线程池最小线程数
	int max_thr_num;                // 线程池最大线程数
	int live_thr_num;               // 当前存活线程个数
	int busy_thr_num;               // 忙状态线程个数
	int wait_exit_thr_num;          // 要销毁的线程个数

	int queue_front;                // 任务队列对头下标
	int queue_rear;                 // 任务队列队尾下标
	int queue_size;                 // 任务队列中的任务数
	int queue_max_size;             // 任务队列中可容纳的任务上限

	int shutdown;                   // 标志位,线程池使用的状态 true/false

};

 

First introduced three functions

threadpool_t* threadpool_create(int min_thr_num, int max_thr_num,
	int queue_max_size);                           // 创建线程池函数

void* threadpool_thread(void* threadpool);         // 线程中各个工作线程


int threadpool_add(threadpool_t* pool, void* (*function)(void* arg), void* arg);   // 向线程池中 添加一个任务

Create a function to initialize the thread pool used for dynamic memory allocation and basic fundamental variables, as well as a certain number of threads started into operation

threadpool_t* threadpool_create(int min_thr_num, int max_thr_num,
	int queue_max_size)
{
	threadpool_t* pool = NULL;
	do {
		// 创建一个线程池
		if ((pool = (threadpool_t*)malloc(sizeof(threadpool_t))) == NULL) {
			printf("malloc threadpool fail\n");
			break;
		}
		// 初始化线程池变量
		pool->min_thr_num = min_thr_num;
		pool->max_thr_num = max_thr_num;
		pool->busy_thr_num = 0;
		pool->live_thr_num = min_thr_num;
		pool->queue_size = 0;
		pool->queue_max_size = queue_max_size;
		pool->queue_front = 0;
		pool->queue_rear = 0;
		pool->shutdown = 0;                         // 不关闭线程池

		// 根据最大线程上限,给工作线程数组开辟空间,并清零。
		pool->threads = (pthread_t*)malloc(sizeof(pthread_t) * max_thr_num);
		if (pool->threads == NULL) {
			printf("malloc threads fail");
			break;
		}
		memset(pool->threads, 0, sizeof(pthread_t) * max_thr_num);

		// 队列开辟空间
		pool->task_queue = (threadpool_task_t*)malloc(sizeof(threadpool_task_t) * queue_max_size);
		if (pool->task_queue == NULL) {
			printf("malloc task_queue fail");
			break;
		}

		// 初始化互斥锁,条件变量
		if (pthread_mutex_init(&(pool->lock), NULL) != 0
			|| pthread_mutex_init(&(pool->thread_counter), NULL) != 0
			|| pthread_cond_init(&(pool->queue_not_empty), NULL) != 0
			|| pthread_cond_init(&(pool->queue_not_full), NULL) != 0) {
			printf("init the lock or cond fail");
			break;
		}
		// 启动 min_thr_num 个work thread
		for (int i = 0; i < min_thr_num; i++) {
			pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void*)pool);
			printf("start thread 0x%x...\n", (unsigned int)pool->threads[i]);
		}
		pthread_create(&(pool->adjust_tid), NULL, adjust_thread, (void*)pool); // 启动管理线程
		return pool;
	} while (0);

	threadpool_free(poll);           // 前面创建失败, 释放poll内存空间。
	return NULL;
}

Adding a task to the task queue, pay attention to when the task queue is full, block waiting, and then perform the basic operations of the team, in order to ensure thread synchronization, locking handle.

// 向线程池中 添加一个任务
int threadpool_add(threadpool_t* pool, void* (*function)(void* arg), void* arg) 
{
	pthread_mutex_lock(&(pool->lock));        // 锁住整个结构体
	// 当队列已经满的时候, 调用wait阻塞
	while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown)) {
		pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));
	}
	if (pool->shutdown) {
		pthread_mutex_unlock(&(pool->lock));
	}

	// 清空 工作线程 调用的回调函数的参数arg;
	if (pool->task_queue[pool->queue_rear].arg != NULL) {
		free(pool->task_queue[pool->queue_rear].arg);
		pool->task_queue[pool->queue_rear].arg = NULL;
	}

	// 添加任务到任务队列里
	pool->task_queue[pool->queue_rear].function = function;
	pool->task_queue[pool->queue_rear].arg = arg;
	pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size;
	pool->queue_size++;

	// 添加完任务后,队列不为空,唤醒线程池中, 等待任务处理的线程
	pthread_cond_signal(&(pool->queue_not_empty));
	pthread_mutex_unlock(&(pool->lock));
	return 0;
}

Thread execution function, first locking structure is removed from the task in the task queue, unlock, and then perform the task.

void* threadpool_thread(void* threadpool)
{
	threadpool_t* pool = (threadpool_t*)threadpool;
	threadpool_task_t task;
	while (1) {
		// 刚创建出线程, 等待任务队列里有任务, 否则阻塞等待任务队列里有任务在唤醒接受任务
		pthread_mutex_lock(&(pool->lock));    // 锁住整个结构体
		// 没有任务,那么阻塞等待
		while ((pool->queue_size == 0) && (!pool->shutdown)) {
			printf("thread 0x%x is waiting\n", (unsigned int)pthread_self());
			pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));

			// 清楚指定数目的空闲线程, 如果要结束的线程个数大于0, 结束线程
			if (pool->wait_exit_thr_num > 0) {
				pool->wait_exit_thr_num--;

				// 如果线程池里里线程的个数大于最小值时可以结束当前线程
				if (pool->live_thr_num > pool->min_thr_num) {
					printf("thread 0x%x is exiting\n", (unsigned int)pthread_self());
					pool->live_thr_num--;
					pthread_mutex_unlock(&(pool->lock));
					pthread_exit(NULL);
				}
			}
		}

		// 要关闭线程池每个线程,线程自行退出
		if (pool->shutdown) {
			pthread_mutex_unlock(&(pool->lock));
			printf("thread 0x%x is exiting\n", (unsigned int)pthread_self());
			pthread_exit(NULL);        // 线程自行结束
		}


		// 从任务队列里获取任务, 出队操作
		task.function = pool->task_queue[pool->queue_front].function;
		task.arg = pool->task_queue[pool->queue_front].arg;

		pool->queue_front = (pool->queue_front + 1) % pool->queue_max_size;
		pool->queue_size--;

		// 通知可以有新的任务添加进来
		pthread_cond_broadcast(&(pool->queue_not_full));

		// 任务取出后,立即将线程池锁释放
		pthread_mutex_unlock(&pool->lock);

		// 执行任务
		printf("thread 0x%x start working\n", (unsigned int)pthread_self());
		pthread_mutex_lock(&(pool->thread_counter));       // 忙线程变量锁
		pool->busy_thr_num++;
		pthread_mutex_unlock(&(pool->thread_counter));
		(*(task.function))(task.arg);                      // 执行回调函数

		// 任务处理结束
		printf("thread 0x%x end working\n", (unsigned int)pthread_self());
		pthread_mutex_lock(&(pool->thread_counter));       // 忙线程变量锁
		pool->busy_thr_num--;
		pthread_mutex_unlock(&(pool->thread_counter));
	}
	pthread_exit(NULL);
}

 

Guess you like

Origin blog.csdn.net/wwxy1995/article/details/94637882