SingleBiu/c_thread_pool: C语言编写的线程池
pool.h:
cpp
/*
* @Author: SingleBiu
* @Date: 2023-03-04 19:21:18
* @LastEditors: SingleBiu
* @LastEditTime: 2023-03-04 19:52:55
* @Description: 线程池头文件
*/
#if !defined(__POOL_H__)
#define __POOL_H__
#include<pthread.h>
#include<string.h>
//构建任务队列结点
typedef struct task_node
{
void *(*task)(void *arg); //函数指针
//一个函数就是一个任务
//一个函数执行完 那么任务就算完成
void *arg; //指向函数的参数
int arg_len; //arg指向对象的长度
struct task_node *next; //指向下一个任务结点
} TASK;
//构建线程池的类型
typedef struct thread_pool
{
pthread_t *p_id; //线程id集合
int task_len; //任务队列长度
int active_thread; //活跃的线程数
int shutdown; //关机位
// 0 进程不结束
// 1 进程结束
TASK *head; //任务队列的头结点
pthread_mutex_t mutex; //锁 保护共享资源
pthread_cond_t cond; //条件变量 用于唤醒线程
} THREAD_POOL;
// 初始化一个线程池 分配一个线程池结构体
THREAD_POOL *init_pool();
// 往线程池的任务队列上添加任务
int add_task(THREAD_POOL *pool, void *(*func)(void *), void *arg, int arg_len);
// 销毁线程池
int destory_pool(THREAD_POOL *pool);
#endif // __POOL_H__
pool.c:
cpp
/*
* @Author: SingleBiu
* @Date: 2023-03-04 19:21:12
* @LastEditors: SingleBiu
* @LastEditTime: 2023-03-05 11:15:02
* @Description: 线程池代码
*/
#include <stdio.h>
#include <stdlib.h>
#include "../inc/pool.h"
#define MAX_THREAD 8 // 线程池最大线程数
/**
* @description: 线程函数
* @param {void} *arg 线程函数参数
* @return {*}
*/
void *func(void *arg)
{
THREAD_POOL *pool = (THREAD_POOL *)arg;
while (1)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_mutex_lock(&pool->mutex);
while (pool->task_len == 0 && pool->shutdown == 0) // 无任务执行 且 未关机
{
pthread_cond_wait(&pool->cond, &pool->mutex); // 线程睡眠
}
// 要么关机 要么执行任务
if (pool->shutdown == 1)
{
pthread_mutex_unlock(&pool->mutex);
pthread_exit(0);
}
// 执行任务
TASK *t = pool->head->next; // 取出开头的任务
pool->head->next = t->next; // 头结点后移
t->next = NULL; // 取下任务结点
pool->task_len--; // 任务数量减一
pthread_mutex_unlock(&pool->mutex); // 之后无需访问共享资源
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
// 执行任务函数
t->task(t->arg);
free(t->arg);
free(t); // 释放申请的空间
}
}
/**
* @description: 初始化线程池
* @return {*}
*/
THREAD_POOL *init_pool()
{
THREAD_POOL *pool = (THREAD_POOL *)malloc(sizeof(*pool));
if (NULL == pool)
{
perror("malloc error\n");
return NULL;
}
pool->task_len = 0; // 任务队列清空
pool->shutdown = 0; // 0 表示不关机
// 创建头结点保证任务队列不为空
pool->head = malloc(sizeof(TASK));
if (pool->head == NULL)
{
free(pool);
perror("mallo error");
return NULL;
}
pool->head->next = NULL; // 指向空 表示任务队列为空
pthread_mutex_init(&pool->mutex, NULL); // 初始化锁
pthread_cond_init(&pool->cond, NULL); // 初始化条件变量
pool->p_id = malloc(sizeof(pthread_t *) * MAX_THREAD); // 线程id集合
pool->active_thread = 0; // 已创建的线程个数
int i; // 线程创建次数
int j = 0; // 线程成功创建次数
for (i = 0; i < MAX_THREAD; i++)
{
if (pthread_create(&pool->p_id[j], NULL, func, pool) != -1)
{
j++;
pool->active_thread++;
printf("success created thread[%d] pid = %ld\n", j, pool->p_id[j]);
}
}
return pool;
}
/**
* @description: 添加任务函数
* @param {THREAD_POOL} *pool 线程池结构体指针
* @param {void} *(*func)(void *) 函数指针
* @param {void} *arg 函数参数
* @param {int} arg_len 函数参数长度
* @return {int} 0 正常 | -1 失败
*/
int add_task(THREAD_POOL *pool, void *(*func)(void *), void *arg, int arg_len)
{
if (NULL == pool)
{
return -1;
}
TASK *new = malloc(sizeof(TASK));
if (NULL == new)
{
perror("malloc error\n");
return -1;
}
new->task = func; // 添加任务函数
new->arg = malloc(arg_len); // 分配参数空间
memcpy(new->arg, arg, arg_len); // 复制参数到申请的空间
new->next = NULL;
pthread_mutex_lock(&pool->mutex); // 保护任务队列
TASK *task = pool->head;
while (NULL != task->next)
{
task = task->next;
}
task->next = new; // 添加任务到队尾
pool->task_len++; // 任务数加一
pthread_cond_signal(&pool->cond); // 唤醒一个线程执行任务
pthread_mutex_unlock(&pool->mutex);
return 0;
}
/**
* @description: 销毁线程池
* @param {THREAD_POOL} *pool 线程池结构体指针
* @return {int} 0 正常 | -1 失败
*/
int destory_pool(THREAD_POOL *pool)
{
pool->shutdown = 1; // 关机位置1
pthread_cond_broadcast(&pool->cond); // 唤醒所有线程自杀
int i;
for (i = 0; i < pool->active_thread; i++)
{
pthread_join(pool->p_id[i],NULL); //回收线程资源
printf("joined thread[%d] pid = %ld\n",i,pool->p_id[i]);
}
free(pool->p_id);
free(pool->head);
free(pool);
return 0;
}
main.c:
cpp
/*
* @Author: SingleBiu
* @Date: 2023-03-04 19:04:13
* @LastEditors: SingleBiu
* @LastEditTime: 2023-03-05 11:30:15
* @Description: 线程池应用
*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include "sys/time.h"
#include "../inc/pool.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int g_ticket = 1000000;
void *get_g_ticket(void *arg)
{
int times = *(int *)arg;
while (g_ticket > 0 && times > 0)
{
if (0 == pthread_mutex_trylock(&mutex))
{
printf("g_ticket1:%d\n", --g_ticket);
pthread_mutex_unlock(&mutex);
times--;
}
else
{
// printf("lock is in use 1\n");
}
}
}
void *get_g_ticket2(void *arg2)
{
int times = *(int *)arg2;
while (g_ticket > 0 && times > 0)
{
if (0 == pthread_mutex_trylock(&mutex))
{
printf("g_ticket2:%d\n", --g_ticket);
pthread_mutex_unlock(&mutex);
times--;
}
else
{
// printf("lock is in use 2\n");
}
}
}
int main(int argc, char const *argv[])
{
THREAD_POOL *thread_pool = init_pool();
int arg = 500000;
int arg2 = 500000;
struct timeval time_start, time_end;
gettimeofday(&time_start, NULL);
add_task(thread_pool, &get_g_ticket, &arg, sizeof(arg));
add_task(thread_pool, &get_g_ticket2, &arg2, sizeof(arg2));
sleep(1);
destory_pool(thread_pool);
gettimeofday(&time_end, NULL);
int timeuse = 1000000 * (time_end.tv_sec - time_start.tv_sec) + time_end.tv_usec - time_start.tv_usec;
printf("Used:%d ms\n", timeuse / 1000);
return 0;
}
makefile:
bash
TARGET := ../bin/main
CC := gcc
CPP := g++ -std=c++11
CSRCS :=$(wildcard *.c)
CPPSRCS :=$(wildcard *.cpp)
O_PATH = ../obj
OBJS := $(patsubst %.c, $(O_PATH)/%.o, $(CSRCS))
OBJS += $(patsubst %.cpp, $(O_PATH)/%.o, $(CPPSRCS))
INC := -I ./ -I ../inc
LIBS := -l pthread
$(TARGET):$(OBJS)
$(CC) $^ $(LIBS) -o $@
$(O_PATH)/%.o:%.c
$(CC) -c $< $(INC) -o $@
$(O_PATH)%.o:%.cpp
$(CPP) -c $< $(INC) -o $@
clean:
rm -rf $(OBJS)
rm -rf $(TARGET)