线程多了,就需要一个线程管理池,线程管理池的工作就是负责开启线程,负责退出线程。
/*线程管理池实现
*
*参考开源代码iiod的实现
*/
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <poll.h>
struct thread_pool
{
pthread_mutex_t thread_count_lock; //计数锁
pthread_cond_t thread_count_cond; //计数条件变量
unsigned int thread_count; //线程池中的线程量
int stop_fd; //停止状态文件描述符
};
struct thread_body_data
{
struct thread_pool* pool; //线程池
void (*f)(struct thread_pool*, void *); //线程执行函数
void *d; //附加用户数据
};
//创建线程池
struct thread_pool *thread_pool_new(void)
{
struct thread_pool *pool;
pool = malloc(sizeof(*pool));
if(!pool)
return NULL;
//创建非阻塞文件描述符
pool->stop_fd = eventfd(0, EFD_NONBLOCK);
if(pool->stop_fd == -1)
{
free(pool);
return NULL;
}
//初始化锁和条件变量
pthread_mutex_init(&pool->thread_count_lock, NULL);
pthread_cond_init(&pool->thread_count_cond, NULL);
pool->thread_count = 0;
return pool;
}
//返回停止状态文件描述符
int thread_pool_get_poll_fd(const struct thread_pool *pool)
{
return pool->stop_fd;
}
//获取退出通知
int thread_pool_get_exit(const struct thread_pool *pool, int msecond)
{
struct pollfd pfd;
pfd.fd = thread_pool_get_poll_fd(pool);
pfd.events = POLLIN;
pfd.revents = 0;
int ret = poll(&pfd, 1, msecond);
if (pfd.revents & POLLIN)
return 1;
return 0;
}
//增加线程计数
static void thread_pool_thread_started(struct thread_pool *pool)
{
pthread_mutex_lock(&pool->thread_count_lock);
pool->thread_count++;
pthread_mutex_unlock(&pool->thread_count_lock);
}
//减少线程计数
static void thread_pool_thread_stopped(struct thread_pool *pool)
{
pthread_mutex_lock(&pool->thread_count_lock);
pool->thread_count--;
pthread_cond_signal(&pool->thread_count_cond);
pthread_mutex_unlock(&pool->thread_count_lock);
}
static void* thread_body(void *d)
{
struct thread_body_data *pdata = d;
//执行线程函数
(*pdata->f)(pdata->pool,pdata->d);
thread_pool_thread_stopped(pdata->pool);
free(pdata);
return NULL;
}
//添加线程任务
int thread_pool_add_thread(struct thread_pool *pool,
void (*f)(struct thread_pool *, void *),
void *d, const char *name)
{
struct thread_body_data* pdata;
sigset_t sigmask,oldsigmask;
pthread_attr_t attr;
pthread_t thd;
int ret;
pdata = malloc(sizeof(*pdata));
if(!pdata)
return -ENOMEM;
pdata->f = f;
pdata->d = d;
pdata->pool = pool;
//线程阻塞所有信号
sigfillset(&sigmask);
pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask);
//设置线程分离
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//增加线程计数
thread_pool_thread_started(pool);
//开始执行线程
ret = pthread_create(&thd, &attr, thread_body, pdata);
if(ret)
{
free(pdata);
thread_pool_thread_stopped(pool);
}
//善后
pthread_attr_destroy(&attr);
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
return ret;
}
//通知进程停止(启动线程中都应主动监听stop_fd的值状态)
void thread_pool_stop(struct thread_pool *pool)
{
uint64_t e = 1;
int ret;
do
{
ret = write(pool->stop_fd, &e, sizeof(e));
} while (ret == -1 && errno == EINTR);
}
//等待所有线程停止
void thread_pool_stop_and_wait(struct thread_pool *pool)
{
uint64_t e;
int ret;
thread_pool_stop(pool);
pthread_mutex_lock(&pool->thread_count_lock);
while(pool->thread_count)
pthread_cond_wait(&pool->thread_count_cond, &pool->thread_count_lock);
pthread_mutex_unlock(&pool->thread_count_lock);
}
//等待所有线程停止
void thread_pool_wait(struct thread_pool *pool)
{
uint64_t e;
int ret;
pthread_mutex_lock(&pool->thread_count_lock);
while(pool->thread_count)
pthread_cond_wait(&pool->thread_count_cond, &pool->thread_count_lock);
pthread_mutex_unlock(&pool->thread_count_lock);
}
//销毁线程池
void thread_pool_destroy(struct thread_pool* pool)
{
pthread_mutex_destroy(&pool->thread_count_lock);
pthread_cond_destroy(&pool->thread_count_cond);
close(pool->stop_fd);
free(pool);
}
线程管理池的调用示例:
#include <stdio.h>
#include "debug.h"
#include "thread_pool.h"
struct thread_pool* pool;
void task1()
{
while(1)
{
int ret = thread_pool_get_exit(pool, 0);
if(ret)
{
DEBUG_LOG("TASK1 EXIT\n")
break;
}
DEBUG_LOG("%s\n","task1 doTask...");
sleep(1);
}
}
void task2()
{
while(1)
{
int ret = thread_pool_get_exit(pool, 0);
if(ret)
{
DEBUG_LOG("TASK2 EXIT\n")
break;
}
DEBUG_LOG("%s\n","task2 doTask...");
sleep(1);
}
}
static void sig_handler(int sig)
{
DEBUG_LOG("received Ctrl C\n")
thread_pool_stop(pool);
}
int main()
{
//自定义信号处理
signal(SIGINT, sig_handler);
pool = thread_pool_new();
thread_pool_add_thread(pool,task1,NULL,"task1");
thread_pool_add_thread(pool,task2,NULL,"task2");
thread_pool_wait(pool);
thread_pool_destroy(pool);
DEBUG_LOG("main EXIT\n");
return 0;
}
示例中开启两个线程,线程的退出由线程管理池的stop_fd来通知。运行结果参考:
需要注意的是,我们自定义了信号SIGINT(也就是Ctrl+C)的处理,当信号发生时,告诉线程管理池打烊了,停下来。否则的话,就会出现下面的这种运行情况:(这感觉就像是坐在火车上正吃着火锅,突然就被土匪给打劫了)