线程管理池

线程多了,就需要一个线程管理池,线程管理池的工作就是负责开启线程,负责退出线程。

/*线程管理池实现
 *
 *参考开源代码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)的处理,当信号发生时,告诉线程管理池打烊了,停下来。否则的话,就会出现下面的这种运行情况:(这感觉就像是坐在火车上正吃着火锅,突然就被土匪给打劫了)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值