线程池的示意图,类似于生产者消费者模式
thread_main.cpp
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "thread_pool.h"
void *func(void *arg)
{
printf("thread %d\n", *(int*)arg);
return NULL;
}
int main(int arg, char **argv)
{
printf("创建线程池。");
if (tpool_create(5) != 0) {
printf("tpool_create failed\n");
exit(1);
}
int n = 20;
int* id = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; ++i)
{
id[i] = i;
tpool_add_work(func, id + i);
}
free(id);
sleep(2);
tpool_destroy();
return 0;
}
thread_pool.h
#ifndef _THREAD_POOL_
#define _THREAD_POOL_
#include <pthread.h>
/* 要执行的任务链表 */
typedef struct tpool_work {
void* (*routine)(void*); /* 任务函数 */
void *arg; /* 传入任务函数的参数 */
struct tpool_work *next;
}tpool_work_t;
typedef struct tpool {
int shutdown; /* 线程池是否销毁 */
int max_thr_num; /* 最大线程数 */
pthread_t *thr_id; /* 线程ID数组 */
tpool_work_t *queue_head; /* 线程链表 */
pthread_mutex_t queue_lock;
pthread_cond_t queue_ready;
}tpool_t;
/*
* @brief 创建线程池
* @param max_thr_num 最大线程数
* @return 0: 成功 其他: 失败
*/
int tpool_create(int max_thr_num);
/*
* @brief 销毁线程池
*/
void tpool_destroy();
/*
* @brief 向线程池中添加任务
* @param routine 任务函数指针
* @param arg 任务函数参数
* @return 0: 成功 其他:失败
*/
int tpool_add_work(void*(*routine)(void*), void *arg);
void tpool_destroy();
#endif
thread_pool.cpp
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "thread_pool.h"
static tpool_t *tpool = NULL;
/* 工作者线程函数, 从任务链表中取出任务并执行 */
static void* thread_routine(void *arg)
{
tpool_work_t *work;
while(1) {
/* 如果线程池没有被销毁且没有任务要执行,则等待 */
pthread_mutex_lock(&tpool->queue_lock);
while(!tpool->queue_head && !tpool->shutdown) {
pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock);
}
if (tpool->shutdown) {
pthread_mutex_unlock(&tpool->queue_lock);
pthread_exit(NULL);
}
work = tpool->queue_head;
tpool->queue_head = tpool->queue_head->next;
pthread_mutex_unlock(&tpool->queue_lock);
work->routine(work->arg);
free(work);
}
return NULL;
}
/*
* 创建线程池
*/
int tpool_create(int max_thr_num)
{
int i;
tpool = (tpool_t*)calloc(1, sizeof(tpool_t));
if (!tpool) {
printf("%s: calloc failed\n", __FUNCTION__);
exit(1);
}
/* 初始化 */
tpool->max_thr_num = max_thr_num;
tpool->shutdown = 0;
tpool->queue_head = NULL;
if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) {
printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n",
__FUNCTION__, errno, strerror(errno));
exit(1);
}
if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) {
printf("%s: pthread_cond_init failed, errno:%d, error:%s\n",
__FUNCTION__, errno, strerror(errno));
exit(1);
}
/* 创建工作者线程 */
tpool->thr_id = (pthread_t*)calloc(max_thr_num, sizeof(pthread_t));
if (!tpool->thr_id) {
printf("%s: calloc failed\n", __FUNCTION__);
exit(1);
}
for (i = 0; i < max_thr_num; ++i) {
if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){
printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__,
errno, strerror(errno));
exit(1);
}
}
return 0;
}
/* 销毁线程池 */
void tpool_destroy()
{
int i;
tpool_work_t *member;
if (tpool->shutdown) {
return;
}
tpool->shutdown = 1;
/* 通知所有正在等待的线程 */
pthread_mutex_lock(&tpool->queue_lock);
pthread_cond_broadcast(&tpool->queue_ready);
pthread_mutex_unlock(&tpool->queue_lock);
for (i = 0; i < tpool->max_thr_num; ++i) {
pthread_join(tpool->thr_id[i], NULL);
}
free(tpool->thr_id);
while(tpool->queue_head) {
member = tpool->queue_head;
tpool->queue_head = tpool->queue_head->next;
free(member);
}
pthread_mutex_destroy(&tpool->queue_lock);
pthread_cond_destroy(&tpool->queue_ready);
free(tpool);
}
/* 向线程池添加任务 */
int tpool_add_work(void*(*routine)(void*), void *arg)
{
tpool_work_t *work, *member;
if (!routine){
printf("%s:Invalid argument\n", __FUNCTION__);
return -1;
}
work = (tpool_work_t*)malloc(sizeof(tpool_work_t));
if (!work) {
printf("%s:malloc failed\n", __FUNCTION__);
return -1;
}
work->routine = routine;
work->arg = arg;
work->next = NULL;
pthread_mutex_lock(&tpool->queue_lock);
member = tpool->queue_head;
if (!member) {
tpool->queue_head = work;
} else {
while(member->next) {
member = member->next;
}
member->next = work;
}
/* 通知工作者线程,有新任务添加 */
pthread_cond_signal(&tpool->queue_ready);
pthread_mutex_unlock(&tpool->queue_lock);
return 0;
}
Makefile
# set CPUS for Linux or FreeBSD
PLATFORM := $(shell uname)
CPUS := $(strip $(if $(shell echo $(PLATFORM)|grep Linux),\
$(shell cat /proc/cpuinfo|grep -c processor),\
$(shell sysctl -a | egrep -i 'hw.ncpu' | cut -d: -f2)))
CC := gcc
CXX := g++
DEBUG := -D_DEBUG
DEBUG := -DNDEBUG -O3
CXXFLAGS := -g $(DEBUG) -fPIC -MMD -Wcast-qual -Wcast-align \
-Wwrite-strings -Wsign-compare -Winvalid-pch -fms-extensions \
-Wfloat-equal -Wextra -Wall -Wno-unused-parameter \
-Wno-unused-function -Wunused-variable -Wunused-value \
-Woverloaded-virtual -Wsign-promo -fno-gnu-keywords -pipe \
-I/usr/local/include \
-I/home/s/include \
-I/home/cloud/zhongchao/.local/token/include \
-I/home/cloud/zhongchao/.local/token/qmodule/qcommon-1.0.1/include \
-I/home/cloud/zhongchao/.local/token/qmodule/segment-2.2.0/include \
-I/home/cloud/zhongchao/.local/token/qmodule/transcode-1.0.0/include \
-I.
LDFLAGS := -L.. \
-L/usr/local/lib \
-L/usr/lib64/ \
-L/home/s/lib \
-L/home/cloud/zhongchao/.local/token/lib \
-L./lib \
-lpthread
ifeq ($(PLATFORM), Linux)
RPATH := -Wl,-rpath
else
RPATH := -rpath
endif
RTFLAGS := \
$(RPATH)=.. \
$(RPATH)=/home/s/lib\
$(RPATH)=/usr/local/lib
SRCS := $(wildcard *.cpp)
OBJS := $(patsubst %.cpp, %.o, $(SRCS))
DEPS := $(patsubst %.o, %.d, $(OBJS))
thread_main : thread_main.o thread_pool.o
$(CXX) $^ $(LDFLAGS) $(RTFLAGS) $(libs) -o $@
$(OBJS) : %.o : %.cpp
$(CC) -c $(CXXFLAGS) $< -o $@
clean:
rm -rf *.d *.o core.* *.out $(TARGET)