c/c++ 多线程入门(四)

啥是线程池?

线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务

避免反复创建线程对象所带来的性能开销,节省了系统的资源。

简单来说就是线程本身存在开销,我们利用多线程来进行任务处理,单线程也不能滥用,无止禁的开新线程会给系统产生大量消耗,而线程本来就是可重用的资源,不需要每次使用时都进行初始化,因此可以采用有限的线程个数处理无限的任务。

在这里插入图片描述
在这里插入图片描述

再看下线程池的常规结构

typedef struct threadpool_t {
	pthread_mutex_t lock;               /* 用于锁住本结构体 ,和条件变量一起使用 */    
	pthread_mutex_t thread_counter;     /* 记录忙状态线程个数的锁 -- busy_thr_num */
	pthread_cond_t queue_not_full;      /* 当任务队列满时,添加任务的线程阻塞,等待此条件变量 */
	pthread_cond_t queue_not_empty;     /* 任务队列里不为空时,通知线程池中等待任务的线程 */
 
	pthread_t *threads;                 /* 存放线程池中每个线程的tid。数组 */
	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;                    /* task_queue队头下标 */
	int queue_rear;                     /* task_queue队尾下标 */
	int queue_size;                     /* task_queue队中实际任务数 */
	int queue_max_size;                 /* task_queue队列可容纳任务数上限 */
 
	int shutdown;                       /* 标志位,线程池使用状态,true或false */
} threadpool_t;

C实现线程池

这里介绍的是线程池的一个简单实现,在创建的时候预先派生指定数量的线程,然后去任务队列取添加进来的任务进行处理就好。

作者说之后会添加更多特性,我们作为学习之后就以这个版本为准就好了。

项目主页:threadpool

项目里 主要有两个自定义的数据结构

threadpool_task_t
用于保存一个等待执行的任务。一个任务需要指明:要运行的对应函数及函数的参数。所以这里的 struct 里有函数指针和 void 指针。

typedef struct {
    void (*function)(void *);
    void *argument;
} threadpool_task_t;

thread_pool_t
一个线程池的结构。因为是 C 语言,所以这里任务队列是用数组,并维护队列头和队列尾来实现。

struct threadpool_t {
  pthread_mutex_t lock;     /* 互斥锁 */
  pthread_cond_t notify;    /* 条件变量 */
  pthread_t *threads;       /* 线程数组的起始指针 */
  threadpool_task_t *queue; /* 任务队列数组的起始指针 */
  int thread_count;         /* 线程数量 */
  int queue_size;           /* 任务队列长度 */
  int head;                 /* 当前任务队列头 */
  int tail;                 /* 当前任务队列尾 */
  int count;                /* 当前待运行的任务数 */
  int shutdown;             /* 线程池当前状态是否关闭 */
  int started;              /* 正在运行的线程数 */
};

函数

对外接口

  • threadpool_t *threadpool_create(int thread_count, int queue_size, int flags);
    创建线程池,用 thread_count 指定派生线程数,queue_size 指定任务队列长度,flags
    为保留参数,未使用。
  • int threadpool_add(threadpool_t *pool, void (*routine)(void *),void *arg, int flags);
    添加需要执行的任务。第二个参数为对应函数指针,第三个为对应函数参数。flags 未使用。
  • int threadpool_destroy(threadpool_t *pool, int flags);
    销毁存在的线程池。flags可以指定是立刻结束还是平和结束。立刻结束指不管任务队列是否为空,立刻结束。平和结束指等待任务队列的任务全部执行完后再结束,在这个过程中不可以添加新的任务。

内部辅助函数

  • static void *threadpool_thread(void *threadpool); 线程池每个线程所执行的函数。
  • int threadpool_free(threadpool_t *pool); 释放线程池所申请的内存资源。

线程池使用

编译
参考项目根目录下的 Makefile, 直接用 make 编译。

测试用例
项目提供了三个测试用例(见 threadpool/test/),我们可以以此来学习线程池的用法并测试是否正常工作。这里提供其中一个:

#define THREAD 32
#define QUEUE  256

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>

#include "threadpool.h"

int tasks = 0, done = 0;
pthread_mutex_t lock;

void dummy_task(void *arg) {
    usleep(10000);
    pthread_mutex_lock(&lock);
    /* 记录成功完成的任务数 */
    done++;
    pthread_mutex_unlock(&lock);
}

int main(int argc, char **argv)
{
    threadpool_t *pool;

    /* 初始化互斥锁 */
    pthread_mutex_init(&lock, NULL);

    /* 断言线程池创建成功 */
    assert((pool = threadpool_create(THREAD, QUEUE, 0)) != NULL);
    fprintf(stderr, "Pool started with %d threads and "
            "queue size of %d\n", THREAD, QUEUE);

    /* 只要任务队列还没满,就一直添加 */
    while(threadpool_add(pool, &dummy_task, NULL, 0) == 0) {
        pthread_mutex_lock(&lock);
        tasks++;
        pthread_mutex_unlock(&lock);
    }

    fprintf(stderr, "Added %d tasks\n", tasks);

    /* 不断检查任务数是否完成一半以上,没有则继续休眠 */
    while((tasks / 2) > done) {
        usleep(10000);
    }
    /* 这时候销毁线程池,0 代表 immediate_shutdown */
    assert(threadpool_destroy(pool, 0) == 0);
    fprintf(stderr, "Did %d tasks\n", done);

    return 0;
}

源码注释一并放在 github, 点我

threadpool.h

/*
 * Copyright (c) 2013, Mathias Brossard <mathias@brossard.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _THREADPOOL_H_
#define _THREADPOOL_H_

#ifdef __cplusplus
/* 对于 C++ 编译器,指定用 C 的语法编译 */
extern "C" {
#endif

/**
 * @file threadpool.h
 * @brief Threadpool Header File
 */

 /**
 * Increase this constants at your own risk
 * Large values might slow down your system
 */
#define MAX_THREADS 64
#define MAX_QUEUE 65536

/* 简化变量定义 */
typedef struct threadpool_t threadpool_t;

/* 定义错误码 */
typedef enum {
    threadpool_invalid        = -1,
    threadpool_lock_failure   = -2,
    threadpool_queue_full     = -3,
    threadpool_shutdown       = -4,
    threadpool_thread_failure = -5
} threadpool_error_t;

typedef enum {
    threadpool_graceful       = 1
} threadpool_destroy_flags_t;

/* 以下是线程池三个对外 API */

/**
 * @function threadpool_create
 * @brief Creates a threadpool_t object.
 * @param thread_count Number of worker threads.
 * @param queue_size   Size of the queue.
 * @param flags        Unused parameter.
 * @return a newly created thread pool or NULL
 */
/**
 * 创建线程池,有 thread_count 个线程,容纳 queue_size 个的任务队列,flags 参数没有使用
 */
threadpool_t *threadpool_create(int thread_count, int queue_size, int flags);

/**
 * @function threadpool_add
 * @brief add a new task in the queue of a thread pool
 * @param pool     Thread pool to which add the task.
 * @param function Pointer to the function that will perform the task.
 * @param argument Argument to be passed to the function.
 * @param flags    Unused parameter.
 * @return 0 if all goes well, negative values in case of error (@see
 * threadpool_error_t for codes).
 */
/**
 *  添加任务到线程池, pool 为线程池指针,routine 为函数指针, arg 为函数参数, flags 未使用
 */
int threadpool_add(threadpool_t *pool, void (*routine)(void *),
                   void *arg, int flags);

/**
 * @function threadpool_destroy
 * @brief Stops and destroys a thread pool.
 * @param pool  Thread pool to destroy.
 * @param flags Flags for shutdown
 *
 * Known values for flags are 0 (default) and threadpool_graceful in
 * which case the thread pool doesn't accept any new tasks but
 * processes all pending tasks before shutdown.
 */
/**
 * 销毁线程池,flags 可以用来指定关闭的方式
 */
int threadpool_destroy(threadpool_t *pool, int flags);

#ifdef __cplusplus
}
#endif

#endif /* _THREADPOOL_H_ */

threadpool.c

/*
 * Copyright (c) 2013, Mathias Brossard <mathias@brossard.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file threadpool.c
 * @brief Threadpool implementation file
 */

#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#include "threadpool.h"

/**
 * 线程池关闭的方式
 */
typedef enum {
    immediate_shutdown = 1,
    graceful_shutdown  = 2
} threadpool_shutdown_t;

/**
 *  @struct threadpool_task
 *  @brief the work struct
 *
 *  @var function Pointer to the function that will perform the task.
 *  @var argument Argument to be passed to the function.
 */
/**
 * 线程池一个任务的定义
 */

typedef struct {
    void (*function)(void *);
    void *argument;
} threadpool_task_t;

/**
 *  @struct threadpool
 *  @brief The threadpool struct
 *
 *  @var notify       Condition variable to notify worker threads.
 *  @var threads      Array containing worker threads ID.
 *  @var thread_count Number of threads
 *  @var queue        Array containing the task queue.
 *  @var queue_size   Size of the task queue.
 *  @var head         Index of the first element.
 *  @var tail         Index of the next element.
 *  @var count        Number of pending tasks
 *  @var shutdown     Flag indicating if the pool is shutting down
 *  @var started      Number of started threads
 */
/**
 * 线程池的结构定义
 *  @var lock         用于内部工作的互斥锁
 *  @var notify       线程间通知的条件变量
 *  @var threads      线程数组,这里用指针来表示,数组名 = 首元素指针
 *  @var thread_count 线程数量
 *  @var queue        存储任务的数组,即任务队列
 *  @var queue_size   任务队列大小
 *  @var head         任务队列中首个任务位置(注:任务队列中所有任务都是未开始运行的)
 *  @var tail         任务队列中最后一个任务的下一个位置(注:队列以数组存储,head 和 tail 指示队列位置)
 *  @var count        任务队列里的任务数量,即等待运行的任务数
 *  @var shutdown     表示线程池是否关闭
 *  @var started      开始的线程数
 */
struct threadpool_t {
  pthread_mutex_t lock;
  pthread_cond_t notify;
  pthread_t *threads;
  threadpool_task_t *queue;
  int thread_count;
  int queue_size;
  int head;
  int tail;
  int count;
  int shutdown;
  int started;
};

/**
 * @function void *threadpool_thread(void *threadpool)
 * @brief the worker thread
 * @param threadpool the pool which own the thread
 */
/**
 * 线程池里每个线程在跑的函数
 * 声明 static 应该只为了使函数只在本文件内有效
 */
static void *threadpool_thread(void *threadpool);

int threadpool_free(threadpool_t *pool);

threadpool_t *threadpool_create(int thread_count, int queue_size, int flags)
{
    if(thread_count <= 0 || thread_count > MAX_THREADS || queue_size <= 0 || queue_size > MAX_QUEUE) {
        return NULL;
    }

    threadpool_t *pool;
    int i;

    /* 申请内存创建内存池对象 */
    if((pool = (threadpool_t *)malloc(sizeof(threadpool_t))) == NULL) {
        goto err;
    }

    /* Initialize */
    pool->thread_count = 0;
    pool->queue_size = queue_size;
    pool->head = pool->tail = pool->count = 0;
    pool->shutdown = pool->started = 0;

    /* Allocate thread and task queue */
    /* 申请线程数组和任务队列所需的内存 */
    pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * thread_count);
    pool->queue = (threadpool_task_t *)malloc
        (sizeof(threadpool_task_t) * queue_size);

    /* Initialize mutex and conditional variable first */
    /* 初始化互斥锁和条件变量 */
    if((pthread_mutex_init(&(pool->lock), NULL) != 0) ||
       (pthread_cond_init(&(pool->notify), NULL) != 0) ||
       (pool->threads == NULL) ||
       (pool->queue == NULL)) {
        goto err;
    }

    /* Start worker threads */
    /* 创建指定数量的线程开始运行 */
    for(i = 0; i < thread_count; i++) {
        if(pthread_create(&(pool->threads[i]), NULL,
                          threadpool_thread, (void*)pool) != 0) {
            threadpool_destroy(pool, 0);
            return NULL;
        }
        pool->thread_count++;
        pool->started++;
    }

    return pool;

 err:
    if(pool) {
        threadpool_free(pool);
    }
    return NULL;
}

int threadpool_add(threadpool_t *pool, void (*function)(void *),
                   void *argument, int flags)
{
    int err = 0;
    int next;

    if(pool == NULL || function == NULL) {
        return threadpool_invalid;
    }

    /* 必须先取得互斥锁所有权 */
    if(pthread_mutex_lock(&(pool->lock)) != 0) {
        return threadpool_lock_failure;
    }

    /* 计算下一个可以存储 task 的位置 */
    next = pool->tail + 1;
    next = (next == pool->queue_size) ? 0 : next;

    do {
        /* Are we full ? */
        /* 检查是否任务队列满 */
        if(pool->count == pool->queue_size) {
            err = threadpool_queue_full;
            break;
        }

        /* Are we shutting down ? */
        /* 检查当前线程池状态是否关闭 */
        if(pool->shutdown) {
            err = threadpool_shutdown;
            break;
        }

        /* Add task to queue */
        /* 在 tail 的位置放置函数指针和参数,添加到任务队列 */
        pool->queue[pool->tail].function = function;
        pool->queue[pool->tail].argument = argument;
        /* 更新 tail 和 count */
        pool->tail = next;
        pool->count += 1;

        /* pthread_cond_broadcast */
        /*
         * 发出 signal,表示有 task 被添加进来了
         * 如果由因为任务队列空阻塞的线程,此时会有一个被唤醒
         * 如果没有则什么都不做
         */
        if(pthread_cond_signal(&(pool->notify)) != 0) {
            err = threadpool_lock_failure;
            break;
        }
        /*
         * 这里用的是 do { ... } while(0) 结构
         * 保证过程最多被执行一次,但在中间方便因为异常而跳出执行块
         */
    } while(0);

    /* 释放互斥锁资源 */
    if(pthread_mutex_unlock(&pool->lock) != 0) {
        err = threadpool_lock_failure;
    }

    return err;
}

int threadpool_destroy(threadpool_t *pool, int flags)
{
    int i, err = 0;

    if(pool == NULL) {
        return threadpool_invalid;
    }

    /* 取得互斥锁资源 */
    if(pthread_mutex_lock(&(pool->lock)) != 0) {
        return threadpool_lock_failure;
    }

    do {
        /* Already shutting down */
        /* 判断是否已在其他地方关闭 */
        if(pool->shutdown) {
            err = threadpool_shutdown;
            break;
        }

        /* 获取指定的关闭方式 */
        pool->shutdown = (flags & threadpool_graceful) ?
            graceful_shutdown : immediate_shutdown;

        /* Wake up all worker threads */
        /* 唤醒所有因条件变量阻塞的线程,并释放互斥锁 */
        if((pthread_cond_broadcast(&(pool->notify)) != 0) ||
           (pthread_mutex_unlock(&(pool->lock)) != 0)) {
            err = threadpool_lock_failure;
            break;
        }

        /* Join all worker thread */
        /* 等待所有线程结束 */
        for(i = 0; i < pool->thread_count; i++) {
            if(pthread_join(pool->threads[i], NULL) != 0) {
                err = threadpool_thread_failure;
            }
        }
        /* 同样是 do{...} while(0) 结构*/
    } while(0);

    /* Only if everything went well do we deallocate the pool */
    if(!err) {
        /* 释放内存资源 */
        threadpool_free(pool);
    }
    return err;
}

int threadpool_free(threadpool_t *pool)
{
    if(pool == NULL || pool->started > 0) {
        return -1;
    }

    /* Did we manage to allocate ? */
    /* 释放线程 任务队列 互斥锁 条件变量 线程池所占内存资源 */
    if(pool->threads) {
        free(pool->threads);
        free(pool->queue);

        /* Because we allocate pool->threads after initializing the
           mutex and condition variable, we're sure they're
           initialized. Let's lock the mutex just in case. */
        pthread_mutex_lock(&(pool->lock));
        pthread_mutex_destroy(&(pool->lock));
        pthread_cond_destroy(&(pool->notify));
    }
    free(pool);
    return 0;
}


static void *threadpool_thread(void *threadpool)
{
    threadpool_t *pool = (threadpool_t *)threadpool;
    threadpool_task_t task;

    for(;;) {
        /* Lock must be taken to wait on conditional variable */
        /* 取得互斥锁资源 */
        pthread_mutex_lock(&(pool->lock));

        /* Wait on condition variable, check for spurious wakeups.
           When returning from pthread_cond_wait(), we own the lock. */
        /* 用 while 是为了在唤醒时重新检查条件 */
        while((pool->count == 0) && (!pool->shutdown)) {
            /* 任务队列为空,且线程池没有关闭时阻塞在这里 */
            pthread_cond_wait(&(pool->notify), &(pool->lock));
        }

        /* 关闭的处理 */
        if((pool->shutdown == immediate_shutdown) ||
           ((pool->shutdown == graceful_shutdown) &&
            (pool->count == 0))) {
            break;
        }

        /* Grab our task */
        /* 取得任务队列的第一个任务 */
        task.function = pool->queue[pool->head].function;
        task.argument = pool->queue[pool->head].argument;
        /* 更新 head 和 count */
        pool->head += 1;
        pool->head = (pool->head == pool->queue_size) ? 0 : pool->head;
        pool->count -= 1;

        /* Unlock */
        /* 释放互斥锁 */
        pthread_mutex_unlock(&(pool->lock));

        /* Get to work */
        /* 开始运行任务 */
        (*(task.function))(task.argument);
        /* 这里一个任务运行结束 */
    }

    /* 线程将结束,更新运行线程数 */
    pool->started--;

    pthread_mutex_unlock(&(pool->lock));
    pthread_exit(NULL);
    return(NULL);
}

以下为 c++实现 线程池类 实现了自动调节池中线程数,功能如上图2所示

/*
==========================================================================
* 类ThreadPool是本代码的核心类,类中自动维护线程池的创建和任务队列的派送

* 其中的TaskFun是任务函数
* 其中的TaskCallbackFun是回调函数

*用法:定义一个ThreadPool变量,TaskFun函数和TaskCallbackFun回调函数,然后调用ThreadPool的QueueTaskItem()函数即可

Author: TTGuoying

Date: 2018/02/19 23:15

==========================================================================
*/
#pragma once
#include <Windows.h>
#include <list>
#include <queue>
#include <memory>

using std::list;
using std::queue;
using std::shared_ptr;

#define THRESHOLE_OF_WAIT_TASK  20

typedef int(*TaskFun)(PVOID param);                // 任务函数
typedef void(*TaskCallbackFun)(int result);        // 回调函数

class ThreadPool
{
private:
    // 线程类(内部类)
    class Thread
    {
    public:
        Thread(ThreadPool *threadPool);
        ~Thread();

        BOOL isBusy();                                                    // 是否有任务在执行
        void ExecuteTask(TaskFun task, PVOID param, TaskCallbackFun taskCallback);    // 执行任务

    private:
        ThreadPool *threadPool;                                            // 所属线程池
        BOOL    busy;                                                    // 是否有任务在执行
        BOOL    exit;                                                    // 是否退出
        HANDLE  thread;                                                    // 线程句柄
        TaskFun    task;                                                    // 要执行的任务
        PVOID    param;                                                    // 任务参数
        TaskCallbackFun taskCb;                                            // 回调的任务
        static unsigned int __stdcall ThreadProc(PVOID pM);                // 线程函数
    };

    // IOCP的通知种类
    enum WAIT_OPERATION_TYPE
    {
        GET_TASK,
        EXIT
    };

    // 待执行的任务类
    class WaitTask
    {
    public:
        WaitTask(TaskFun task, PVOID param, TaskCallbackFun taskCb, BOOL bLong)
        {
            this->task = task;
            this->param = param;
            this->taskCb = taskCb;
            this->bLong = bLong;
        }
        ~WaitTask() { task = NULL; taskCb = NULL; bLong = FALSE; param = NULL; }

        TaskFun    task;                    // 要执行的任务
        PVOID param;                    // 任务参数
        TaskCallbackFun taskCb;            // 回调的任务
        BOOL bLong;                        // 是否时长任务
    };

    // 从任务列表取任务的线程函数
    static unsigned int __stdcall GetTaskThreadProc(PVOID pM)
    {
        ThreadPool *threadPool = (ThreadPool *)pM;
        BOOL bRet = FALSE;
        DWORD dwBytes = 0;
        WAIT_OPERATION_TYPE opType;
        OVERLAPPED *ol;
        while (WAIT_OBJECT_0 != WaitForSingleObject(threadPool->stopEvent, 0))
        {
            BOOL bRet = GetQueuedCompletionStatus(threadPool->completionPort, &dwBytes, (PULONG_PTR)&opType, &ol, INFINITE);
            // 收到退出标志
            if (EXIT == (DWORD)opType)
            {
                break;
            }
            else if (GET_TASK == (DWORD)opType)
            {
                threadPool->GetTaskExcute();
            }
        }
        return 0;
    }

    //线程临界区锁
    class CriticalSectionLock
    {
    private:
        CRITICAL_SECTION cs;//临界区
    public:
        CriticalSectionLock() { InitializeCriticalSection(&cs); }
        ~CriticalSectionLock() { DeleteCriticalSection(&cs); }
        void Lock() { EnterCriticalSection(&cs); }
        void UnLock() { LeaveCriticalSection(&cs); }
    };


public:
    ThreadPool(size_t minNumOfThread = 2, size_t maxNumOfThread = 10);
    ~ThreadPool();

    BOOL QueueTaskItem(TaskFun task, PVOID param, TaskCallbackFun taskCb = NULL, BOOL longFun = FALSE);       // 任务入队

private:
    size_t getCurNumOfThread() { return getIdleThreadNum() + getBusyThreadNum(); }    // 获取线程池中的当前线程数
    size_t GetMaxNumOfThread() { return maxNumOfThread - numOfLongFun; }            // 获取线程池中的最大线程数
    void SetMaxNumOfThread(size_t size)            // 设置线程池中的最大线程数
    {
        if (size < numOfLongFun)
        {
            maxNumOfThread = size + numOfLongFun;
        }
        else
            maxNumOfThread = size;
    }
    size_t GetMinNumOfThread() { return minNumOfThread; }                            // 获取线程池中的最小线程数
    void SetMinNumOfThread(size_t size) { minNumOfThread = size; }                    // 设置线程池中的最小线程数

    size_t getIdleThreadNum() { return idleThreadList.size(); }    // 获取线程池中的线程数
    size_t getBusyThreadNum() { return busyThreadList.size(); }    // 获取线程池中的线程数
    void CreateIdleThread(size_t size);                            // 创建空闲线程
    void DeleteIdleThread(size_t size);                            // 删除空闲线程
    Thread *GetIdleThread();                                    // 获取空闲线程
    void MoveBusyThreadToIdleList(Thread *busyThread);            // 忙碌线程加入空闲列表
    void MoveThreadToBusyList(Thread *thread);                    // 线程加入忙碌列表
    void GetTaskExcute();                                        // 从任务队列中取任务执行
    WaitTask *GetTask();                                        // 从任务队列中取任务

    CriticalSectionLock idleThreadLock;                            // 空闲线程列表锁
    list<Thread *> idleThreadList;                                // 空闲线程列表
    CriticalSectionLock busyThreadLock;                            // 忙碌线程列表锁
    list<Thread *> busyThreadList;                                // 忙碌线程列表

    CriticalSectionLock waitTaskLock;
    list<WaitTask *> waitTaskList;                                // 任务列表

    HANDLE                    dispatchThrad;                        // 分发任务线程
    HANDLE                    stopEvent;                            // 通知线程退出的时间
    HANDLE                    completionPort;                        // 完成端口
    size_t                    maxNumOfThread;                        // 线程池中最大的线程数
    size_t                    minNumOfThread;                        // 线程池中最小的线程数
    size_t                    numOfLongFun;                        // 线程池中最小的线程数
};
#include "stdafx.h"
#include "ThreadPool.h"
#include <process.h>


ThreadPool::ThreadPool(size_t minNumOfThread, size_t maxNumOfThread)
{
    if (minNumOfThread < 2)
        this->minNumOfThread = 2;
    else
        this->minNumOfThread = minNumOfThread;
    if (maxNumOfThread < this->minNumOfThread * 2)
        this->maxNumOfThread = this->minNumOfThread * 2;
    else
        this->maxNumOfThread = maxNumOfThread;
    stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);

    idleThreadList.clear();
    CreateIdleThread(this->minNumOfThread);
    busyThreadList.clear();

    dispatchThrad = (HANDLE)_beginthreadex(0, 0, GetTaskThreadProc, this, 0, 0);
    numOfLongFun = 0;
}

ThreadPool::~ThreadPool()
{
    SetEvent(stopEvent);
    PostQueuedCompletionStatus(completionPort, 0, (DWORD)EXIT, NULL);

    CloseHandle(stopEvent);
}

BOOL ThreadPool::QueueTaskItem(TaskFun task, PVOID param, TaskCallbackFun taskCb, BOOL longFun)
{
    waitTaskLock.Lock();
    WaitTask *waitTask = new WaitTask(task, param, taskCb, longFun);
    waitTaskList.push_back(waitTask);
    waitTaskLock.UnLock();
    PostQueuedCompletionStatus(completionPort, 0, (DWORD)GET_TASK, NULL);
    return TRUE;
}

void ThreadPool::CreateIdleThread(size_t size)
{
    idleThreadLock.Lock();
    for (size_t i = 0; i < size; i++)
    {
        idleThreadList.push_back(new Thread(this));
    }
    idleThreadLock.UnLock();
}

void ThreadPool::DeleteIdleThread(size_t size)
{
    idleThreadLock.Lock();
    size_t t = idleThreadList.size();
    if (t >= size)
    {
        for (size_t i = 0; i < size; i++)
        {
            auto thread = idleThreadList.back();
            delete thread;
            idleThreadList.pop_back();
        }
    }
    else
    {
        for (size_t i = 0; i < t; i++)
        {
            auto thread = idleThreadList.back();
            delete thread;
            idleThreadList.pop_back();
        }
    }
    idleThreadLock.UnLock();
}

ThreadPool::Thread *ThreadPool::GetIdleThread()
{
    Thread *thread = NULL;
    idleThreadLock.Lock();
    if (idleThreadList.size() > 0)
    {
        thread = idleThreadList.front();
        idleThreadList.pop_front();
    }
    idleThreadLock.UnLock();

    if (thread == NULL && getCurNumOfThread() < maxNumOfThread)
    {
        thread = new Thread(this);
    }

    if (thread == NULL && waitTaskList.size() > THRESHOLE_OF_WAIT_TASK)
    {
        thread = new Thread(this);
        InterlockedIncrement(&maxNumOfThread);
    }
    return thread;
}

void ThreadPool::MoveBusyThreadToIdleList(Thread * busyThread)
{
    idleThreadLock.Lock();
    idleThreadList.push_back(busyThread);
    idleThreadLock.UnLock();

    busyThreadLock.Lock();
    for (auto it = busyThreadList.begin(); it != busyThreadList.end(); it++)
    {
        if (*it == busyThread)
        {
            busyThreadList.erase(it);
            break;
        }
    }
    busyThreadLock.UnLock();

    if (maxNumOfThread != 0 && idleThreadList.size() > maxNumOfThread * 0.8)
    {
        DeleteIdleThread(idleThreadList.size() / 2);
    }

    PostQueuedCompletionStatus(completionPort, 0, (DWORD)GET_TASK, NULL);
}

void ThreadPool::MoveThreadToBusyList(Thread * thread)
{
    busyThreadLock.Lock();
    busyThreadList.push_back(thread);
    busyThreadLock.UnLock();
}

void ThreadPool::GetTaskExcute()
{
    Thread *thread = NULL;
    WaitTask *waitTask = NULL;

    waitTask = GetTask();
    if (waitTask == NULL)
    {
        return;
    }

    if (waitTask->bLong)
    {
        if (idleThreadList.size() > minNumOfThread)
        {
            thread = GetIdleThread();
        }
        else
        {
            thread = new Thread(this);
            InterlockedIncrement(&numOfLongFun);
            InterlockedIncrement(&maxNumOfThread);
        }
    }
    else
    {
        thread = GetIdleThread();
    }

    if (thread != NULL)
    {
        thread->ExecuteTask(waitTask->task, waitTask->param, waitTask->taskCb);
        delete waitTask;
        MoveThreadToBusyList(thread);
    }
    else
    {
        waitTaskLock.Lock();
        waitTaskList.push_front(waitTask);
        waitTaskLock.UnLock();
    }

}

ThreadPool::WaitTask *ThreadPool::GetTask()
{
    WaitTask *waitTask = NULL;
    waitTaskLock.Lock();
    if (waitTaskList.size() > 0)
    {
        waitTask = waitTaskList.front();
        waitTaskList.pop_front();
    }
    waitTaskLock.UnLock();
    return waitTask;
}


ThreadPool::Thread::Thread(ThreadPool *threadPool) :
    busy(FALSE),
    thread(INVALID_HANDLE_VALUE),
    task(NULL),
    taskCb(NULL),
    exit(FALSE),
    threadPool(threadPool)
{
    thread = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, CREATE_SUSPENDED, 0);
}

ThreadPool::Thread::~Thread()
{
    exit = TRUE;
    task = NULL;
    taskCb = NULL;
    ResumeThread(thread);
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);
}

BOOL ThreadPool::Thread::isBusy()
{
    return busy;
}

void ThreadPool::Thread::ExecuteTask(TaskFun task, PVOID param, TaskCallbackFun taskCallback)
{
    busy = TRUE;
    this->task = task;
    this->param = param;
    this->taskCb = taskCallback;
    ResumeThread(thread);
}

unsigned int ThreadPool::Thread::ThreadProc(PVOID pM)
{
    Thread *pThread = (Thread*)pM;

    while (true)
    {
        if (pThread->exit)
            break; //线程退出

        if (pThread->task == NULL && pThread->taskCb == NULL)
        {
            pThread->busy = FALSE;
            pThread->threadPool->MoveBusyThreadToIdleList(pThread);
            SuspendThread(pThread->thread);
            continue;
        }

        int resulst = pThread->task(pThread->param);
        if(pThread->taskCb)
            pThread->taskCb(resulst);
        WaitTask *waitTask = pThread->threadPool->GetTask();
        if (waitTask != NULL)
        {
            pThread->task = waitTask->task;
            pThread->taskCb = waitTask->taskCb;
            delete waitTask;
            continue;
        }
        else
        {
            pThread->task = NULL;
            pThread->param = NULL;
            pThread->taskCb = NULL;
            pThread->busy = FALSE;
            pThread->threadPool->MoveBusyThreadToIdleList(pThread);
            SuspendThread(pThread->thread);
        }
    }

    return 0;
}
#include "stdafx.h"
#include "ThreadPool.h"
#include <process.h>


ThreadPool::ThreadPool(size_t minNumOfThread, size_t maxNumOfThread)
{
    if (minNumOfThread < 2)
        this->minNumOfThread = 2;
    else
        this->minNumOfThread = minNumOfThread;
    if (maxNumOfThread < this->minNumOfThread * 2)
        this->maxNumOfThread = this->minNumOfThread * 2;
    else
        this->maxNumOfThread = maxNumOfThread;
    stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);

    idleThreadList.clear();
    CreateIdleThread(this->minNumOfThread);
    busyThreadList.clear();

    dispatchThrad = (HANDLE)_beginthreadex(0, 0, GetTaskThreadProc, this, 0, 0);
    numOfLongFun = 0;
}

ThreadPool::~ThreadPool()
{
    SetEvent(stopEvent);
    PostQueuedCompletionStatus(completionPort, 0, (DWORD)EXIT, NULL);

    CloseHandle(stopEvent);
}

BOOL ThreadPool::QueueTaskItem(TaskFun task, PVOID param, TaskCallbackFun taskCb, BOOL longFun)
{
    waitTaskLock.Lock();
    WaitTask *waitTask = new WaitTask(task, param, taskCb, longFun);
    waitTaskList.push_back(waitTask);
    waitTaskLock.UnLock();
    PostQueuedCompletionStatus(completionPort, 0, (DWORD)GET_TASK, NULL);
    return TRUE;
}

void ThreadPool::CreateIdleThread(size_t size)
{
    idleThreadLock.Lock();
    for (size_t i = 0; i < size; i++)
    {
        idleThreadList.push_back(new Thread(this));
    }
    idleThreadLock.UnLock();
}

void ThreadPool::DeleteIdleThread(size_t size)
{
    idleThreadLock.Lock();
    size_t t = idleThreadList.size();
    if (t >= size)
    {
        for (size_t i = 0; i < size; i++)
        {
            auto thread = idleThreadList.back();
            delete thread;
            idleThreadList.pop_back();
        }
    }
    else
    {
        for (size_t i = 0; i < t; i++)
        {
            auto thread = idleThreadList.back();
            delete thread;
            idleThreadList.pop_back();
        }
    }
    idleThreadLock.UnLock();
}

ThreadPool::Thread *ThreadPool::GetIdleThread()
{
    Thread *thread = NULL;
    idleThreadLock.Lock();
    if (idleThreadList.size() > 0)
    {
        thread = idleThreadList.front();
        idleThreadList.pop_front();
    }
    idleThreadLock.UnLock();

    if (thread == NULL && getCurNumOfThread() < maxNumOfThread)
    {
        thread = new Thread(this);
    }

    if (thread == NULL && waitTaskList.size() > THRESHOLE_OF_WAIT_TASK)
    {
        thread = new Thread(this);
        InterlockedIncrement(&maxNumOfThread);
    }
    return thread;
}

void ThreadPool::MoveBusyThreadToIdleList(Thread * busyThread)
{
    idleThreadLock.Lock();
    idleThreadList.push_back(busyThread);
    idleThreadLock.UnLock();

    busyThreadLock.Lock();
    for (auto it = busyThreadList.begin(); it != busyThreadList.end(); it++)
    {
        if (*it == busyThread)
        {
            busyThreadList.erase(it);
            break;
        }
    }
    busyThreadLock.UnLock();

    if (maxNumOfThread != 0 && idleThreadList.size() > maxNumOfThread * 0.8)
    {
        DeleteIdleThread(idleThreadList.size() / 2);
    }

    PostQueuedCompletionStatus(completionPort, 0, (DWORD)GET_TASK, NULL);
}

void ThreadPool::MoveThreadToBusyList(Thread * thread)
{
    busyThreadLock.Lock();
    busyThreadList.push_back(thread);
    busyThreadLock.UnLock();
}

void ThreadPool::GetTaskExcute()
{
    Thread *thread = NULL;
    WaitTask *waitTask = NULL;

    waitTask = GetTask();
    if (waitTask == NULL)
    {
        return;
    }

    if (waitTask->bLong)
    {
        if (idleThreadList.size() > minNumOfThread)
        {
            thread = GetIdleThread();
        }
        else
        {
            thread = new Thread(this);
            InterlockedIncrement(&numOfLongFun);
            InterlockedIncrement(&maxNumOfThread);
        }
    }
    else
    {
        thread = GetIdleThread();
    }

    if (thread != NULL)
    {
        thread->ExecuteTask(waitTask->task, waitTask->param, waitTask->taskCb);
        delete waitTask;
        MoveThreadToBusyList(thread);
    }
    else
    {
        waitTaskLock.Lock();
        waitTaskList.push_front(waitTask);
        waitTaskLock.UnLock();
    }

}

ThreadPool::WaitTask *ThreadPool::GetTask()
{
    WaitTask *waitTask = NULL;
    waitTaskLock.Lock();
    if (waitTaskList.size() > 0)
    {
        waitTask = waitTaskList.front();
        waitTaskList.pop_front();
    }
    waitTaskLock.UnLock();
    return waitTask;
}


ThreadPool::Thread::Thread(ThreadPool *threadPool) :
    busy(FALSE),
    thread(INVALID_HANDLE_VALUE),
    task(NULL),
    taskCb(NULL),
    exit(FALSE),
    threadPool(threadPool)
{
    thread = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, CREATE_SUSPENDED, 0);
}

ThreadPool::Thread::~Thread()
{
    exit = TRUE;
    task = NULL;
    taskCb = NULL;
    ResumeThread(thread);
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);
}

BOOL ThreadPool::Thread::isBusy()
{
    return busy;
}

void ThreadPool::Thread::ExecuteTask(TaskFun task, PVOID param, TaskCallbackFun taskCallback)
{
    busy = TRUE;
    this->task = task;
    this->param = param;
    this->taskCb = taskCallback;
    ResumeThread(thread);
}

unsigned int ThreadPool::Thread::ThreadProc(PVOID pM)
{
    Thread *pThread = (Thread*)pM;

    while (true)
    {
        if (pThread->exit)
            break; //线程退出

        if (pThread->task == NULL && pThread->taskCb == NULL)
        {
            pThread->busy = FALSE;
            pThread->threadPool->MoveBusyThreadToIdleList(pThread);
            SuspendThread(pThread->thread);
            continue;
        }

        int resulst = pThread->task(pThread->param);
        if(pThread->taskCb)
            pThread->taskCb(resulst);
        WaitTask *waitTask = pThread->threadPool->GetTask();
        if (waitTask != NULL)
        {
            pThread->task = waitTask->task;
            pThread->taskCb = waitTask->taskCb;
            delete waitTask;
            continue;
        }
        else
        {
            pThread->task = NULL;
            pThread->param = NULL;
            pThread->taskCb = NULL;
            pThread->busy = FALSE;
            pThread->threadPool->MoveBusyThreadToIdleList(pThread);
            SuspendThread(pThread->thread);
        }
    }

    return 0;
}

转载自 https://www.cnblogs.com/tanguoying/p/8454637.html
https://blog.csdn.net/jcjc918/article/details/50395528

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值