基于linux的多线程处理程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <stdbool.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <pthread.h>

#define DEBUG //调试信息

#ifndef DEBUG
#define debug(...)
#else
//#ifdef DEBUG
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
#define debug(...)                                                        \
    do                                                                    \
    {                                                                     \
        fprintf(stdout, "%s: %s:%d: ", __FILE__, __FUNCTION__, __LINE__); \
        fprintf(stdout, __VA_ARGS__);                                     \
        putc('\n', stdout);                                               \
    } while (0)
#else
#define debug(args...)                                                    \
    do                                                                    \
    {                                                                     \
        fprintf(stdout, "%s: %s:%d: ", __FILE__, __FUNCTION__, __LINE__); \
        fprintf(stdout, ##args);                                          \
        putc('\n', stdout);                                               \
    } while (0)
#endif
#endif // DEBUG

#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
#define error(...)                                                        \
    do                                                                    \
    {                                                                     \
        fprintf(stderr, "%s: %s:%d: ", __FILE__, __FUNCTION__, __LINE__); \
        fprintf(stderr, __VA_ARGS__);                                     \
        putc('\n', stderr);                                               \
    } while (0)
#else
#define error(args...)                                                    \
    do                                                                    \
    {                                                                     \
        fprintf(stderr, "%s: %s:%d: ", __FILE__, __FUNCTION__, __LINE__); \
        fprintf(stderr, ##args);                                          \
        putc('\n', stderr);                                               \
    } while (0)
#endif


#define WORKER_MULTIPLE_TASK_NUMBER 10

typedef struct worker_task_struct
{
    void *(*process)(void *arg);
    void *arg;
    struct worker_task_struct *next;
} worker_task_t;

typedef struct threads_pool_struct
{
    worker_task_t *pend_queue_head; /**< 任务结点链表,保存所有投递的任务 */
    worker_task_t *free_queue_head;
    int max_task_num;
    int current_pend_task_num;
    worker_task_t *tasks_ptr;

    int shutdown; /**< 线程池销毁标志,1 -> 销毁 */
    pthread_t *workers_id;
    pthread_mutex_t queue_lock; /**< 互斥锁 */
    pthread_cond_t queue_ready; /**< 条件变量 */

    int max_worker_num;
    int current_process_worker_num;

    void *(*func_routine)(void *arg); //常规函数(空闲)

} threads_pool_t;

static void *threads_pool_default_routine(void *arg)
{
    assert(arg);

    threads_pool_t *base = (threads_pool_t *)arg;

    debug("ready to go [%x]", pthread_self());

    while (1)
    {
        pthread_mutex_lock(&(base->queue_lock)); /**< 上锁, pthread_cond_wait()调用会解锁*/

        while ((base->current_pend_task_num == 0) && (!base->shutdown)) /**< 队列没有等待任务*/
        {
            debug("wait for [%x]", pthread_self());
            pthread_cond_wait(&(base->queue_ready), &(base->queue_lock)); /**< 条件锁阻塞等待条件信号*/
        }

        if (base->shutdown)
        {
            debug("shut down [0x%x]", pthread_self());
            pthread_mutex_unlock(&(base->queue_lock));
            pthread_exit(NULL); /**< 释放线程 */
            debug("unable to this [%x]", pthread_self());
            break;
        }

        base->current_process_worker_num++;

        worker_task_t *task = base->pend_queue_head; /**< 取等待队列任务结点头*/
        base->pend_queue_head = task->next;          /**< 链表后移 */
        base->current_pend_task_num--;

        pthread_mutex_unlock(&(base->queue_lock));
        (*(task->process))(task->arg); /**< 执行回调函数 */
        pthread_mutex_lock(&(base->queue_lock));

        task->next = base->free_queue_head;
        base->free_queue_head = task;

        base->current_process_worker_num--;
        pthread_mutex_unlock(&(base->queue_lock));
    }

    return 0;
}

int threads_pool_init(threads_pool_t *base, int max_thread_num)
{
    assert(!base->workers_id);
    assert(!base->pend_queue_head);
    assert(!base->free_queue_head);

    base->shutdown = 0;
    pthread_mutex_init(&(base->queue_lock), NULL); /**< 初始化互斥锁 */
    pthread_cond_init(&(base->queue_ready), NULL); /**< 初始化条件变量 */

    /**< 创建任务 */
    int task_num = max_thread_num * WORKER_MULTIPLE_TASK_NUMBER;
    worker_task_t *tasks = (worker_task_t *)malloc(sizeof(worker_task_t) * task_num);
    for (int j = 0; j < (task_num - 1); j++)
    {
        tasks[j].next = &(tasks[j + 1]);
    }
    tasks[task_num - 1].next = NULL;
    base->free_queue_head = base->tasks_ptr = tasks;
    base->max_task_num = task_num;
    debug("max task num is %d", task_num);

    base->workers_id = (pthread_t *)malloc(sizeof(pthread_t) * max_thread_num);
    base->func_routine = threads_pool_default_routine;
    base->current_process_worker_num = 0;

    for (int i = 0; i < max_thread_num; i++)
    {
        /**< 创建线程 */
        if (!pthread_create(&(base->workers_id[i]), NULL, base->func_routine, (void *)base))
        {
            debug("create thread id is %d:[%x]", i, base->workers_id[i]);
            base->max_worker_num++; /**< 当前池中的线程数 */
        }
        else
        {
            error("create worker failed");
            break;
        }
        usleep(1000);
    }

    return 0;
}

int threads_pool_destroy(threads_pool_t *base)
{
    debug("destroy");

    if (base->shutdown) /**< 已销毁 */
    {
        error("already close!");
        return -1;
    }

    base->shutdown = 1;                           /**< 销毁标志置位 */
    pthread_cond_broadcast(&(base->queue_ready)); /**< 唤醒所有pthread_cond_wait()等待线程 */
    debug("broadcast workers to shut down");

    for (int i = 0; i < base->max_worker_num; i++)
    {
        pthread_join(base->workers_id[i], NULL); /**< 等待所有线程执行结束 */
        debug("destroy worker id is %d:[%x]", i, base->workers_id[i]);
    }
    free(base->workers_id); /**< 释放 */
    debug("free workers");

    free(base->tasks_ptr); /**< 释放 */
    debug("free tasks");

    pthread_mutex_destroy(&(base->queue_lock)); /**< 销毁 */
    pthread_cond_destroy(&(base->queue_ready)); /**< 销毁 */

    return 0;
}

int threads_pool_task_status(threads_pool_t *base, int *pend_task_num, int *process_task_num)
{
    assert(base);

    pthread_mutex_lock(&(base->queue_lock));
    if (pend_task_num)
        *pend_task_num = base->current_pend_task_num;
    debug("current pend task num is %d", base->current_pend_task_num);
    if (process_task_num)
        *process_task_num = base->current_process_worker_num;
    debug("current process task num is %d", base->current_process_worker_num);
    pthread_mutex_unlock(&(base->queue_lock));

    return 0;
}

int threads_pool_submit_task(threads_pool_t *base, void *(*process)(void *arg), void *arg)
{
    assert(base);
    assert(process);

    worker_task_t *task;
    do
    {
        pthread_mutex_lock(&(base->queue_lock));
        task = base->free_queue_head;
        if (task)
        {
            base->free_queue_head = task->next;
            task->process = process;
            task->arg = arg;
            task->next = base->pend_queue_head;
            base->pend_queue_head = task;
            base->current_pend_task_num++;
            debug("current pend task num is %d", base->current_pend_task_num);
        }
        else
        {
            error("not free task to use");
        }
        pthread_mutex_unlock(&(base->queue_lock));
    } while (!task && !usleep(1000)); /**< 等待有空闲任务 */

    pthread_cond_signal(&(base->queue_ready)); /**< 发送信号给1个处于条件阻塞等待状态的线程 */
    return 0;
}

测试代码:

void *handle_say_hello(void *arg)
{
    printf("hello world\n");
    return NULL;
}

int main(int argc, char *argv[])
{ 
    //  创建处理连接的线程池
    threads_pool_t tpool;
    memset(&tpool, 0, sizeof(threads_pool_t));
    threads_pool_init(&tpool, 3);
    for (size_t i = 0; i < 50; i++)
    {
        threads_pool_submit_task(&tpool, handle_say_hello, NULL);
    }
    int pend_num, process_num;
    threads_pool_task_status(&tpool, &pend_num, &process_num);
    usleep(1000);
    threads_pool_task_status(&tpool, &pend_num, &process_num);
    threads_pool_destroy(&tpool);

    return 0;
}

测试结果:

ras_server.c: threads_pool_init:163: max task num is 30
ras_server.c: threads_pool_init:174: create thread id is 0:[94d0a700]
ras_server.c: threads_pool_default_routine:102: ready to go [94d0a700]
ras_server.c: threads_pool_default_routine:110: wait for [94d0a700]
ras_server.c: threads_pool_init:174: create thread id is 1:[94509700]
ras_server.c: threads_pool_default_routine:102: ready to go [94509700]
ras_server.c: threads_pool_default_routine:110: wait for [94509700]
ras_server.c: threads_pool_init:174: create thread id is 2:[93d08700]
ras_server.c: threads_pool_default_routine:102: ready to go [93d08700]
ras_server.c: threads_pool_default_routine:110: wait for [93d08700]
ras_server.c: threads_pool_submit_task:253: current pend task num is 1
ras_server.c: threads_pool_submit_task:253: current pend task num is 2
ras_server.c: threads_pool_submit_task:253: current pend task num is 3
ras_server.c: threads_pool_submit_task:253: current pend task num is 4
ras_server.c: threads_pool_submit_task:253: current pend task num is 5
ras_server.c: threads_pool_submit_task:253: current pend task num is 6
ras_server.c: threads_pool_submit_task:253: current pend task num is 7
ras_server.c: threads_pool_submit_task:253: current pend task num is 8
ras_server.c: threads_pool_submit_task:253: current pend task num is 9
ras_server.c: threads_pool_submit_task:253: current pend task num is 10
ras_server.c: threads_pool_submit_task:253: current pend task num is 11
ras_server.c: threads_pool_submit_task:253: current pend task num is 12
ras_server.c: threads_pool_submit_task:253: current pend task num is 13
ras_server.c: threads_pool_submit_task:253: current pend task num is 14
ras_server.c: threads_pool_submit_task:253: current pend task num is 15
ras_server.c: threads_pool_submit_task:253: current pend task num is 16
ras_server.c: threads_pool_submit_task:253: current pend task num is 17
ras_server.c: threads_pool_submit_task:253: current pend task num is 18
ras_server.c: threads_pool_submit_task:253: current pend task num is 19
ras_server.c: threads_pool_submit_task:253: current pend task num is 20
ras_server.c: threads_pool_submit_task:253: current pend task num is 21
ras_server.c: threads_pool_submit_task:253: current pend task num is 22
ras_server.c: threads_pool_submit_task:253: current pend task num is 23
ras_server.c: threads_pool_submit_task:253: current pend task num is 24
ras_server.c: threads_pool_submit_task:253: current pend task num is 25
ras_server.c: threads_pool_submit_task:253: current pend task num is 26
ras_server.c: threads_pool_submit_task:253: current pend task num is 27
ras_server.c: threads_pool_submit_task:253: current pend task num is 28
ras_server.c: threads_pool_submit_task:253: current pend task num is 29
ras_server.c: threads_pool_submit_task:253: current pend task num is 30
ras_server.c: threads_pool_submit_task:257: not free task to use
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
ras_server.c: threads_pool_default_routine:110: wait for [94d0a700]
ras_server.c: threads_pool_default_routine:110: wait for [93d08700]
ras_server.c: threads_pool_default_routine:110: wait for [94509700]
ras_server.c: threads_pool_submit_task:253: current pend task num is 1
ras_server.c: threads_pool_submit_task:253: current pend task num is 2
ras_server.c: threads_pool_submit_task:253: current pend task num is 3
ras_server.c: threads_pool_submit_task:253: current pend task num is 4
ras_server.c: threads_pool_submit_task:253: current pend task num is 5
ras_server.c: threads_pool_submit_task:253: current pend task num is 6
ras_server.c: threads_pool_submit_task:253: current pend task num is 7
ras_server.c: threads_pool_submit_task:253: current pend task num is 8
ras_server.c: threads_pool_submit_task:253: current pend task num is 9
ras_server.c: threads_pool_submit_task:253: current pend task num is 10
ras_server.c: threads_pool_submit_task:253: current pend task num is 11
ras_server.c: threads_pool_submit_task:253: current pend task num is 12
ras_server.c: threads_pool_submit_task:253: current pend task num is 13
ras_server.c: threads_pool_submit_task:253: current pend task num is 14
ras_server.c: threads_pool_submit_task:253: current pend task num is 15
ras_server.c: threads_pool_submit_task:253: current pend task num is 16
ras_server.c: threads_pool_submit_task:253: current pend task num is 17
ras_server.c: threads_pool_submit_task:253: current pend task num is 18
ras_server.c: threads_pool_submit_task:253: current pend task num is 19
ras_server.c: threads_pool_submit_task:253: current pend task num is 20
ras_server.c: threads_pool_task_status:226: current pend task num is 20
ras_server.c: threads_pool_task_status:229: current process task num is 0
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
ras_server.c: threads_pool_default_routine:110: wait for [93d08700]
hello world
ras_server.c: threads_pool_default_routine:110: wait for [94d0a700]
hello world
ras_server.c: threads_pool_default_routine:110: wait for [94509700]
ras_server.c: threads_pool_task_status:226: current pend task num is 0
ras_server.c: threads_pool_task_status:229: current process task num is 0
ras_server.c: threads_pool_destroy:190: destroy
ras_server.c: threads_pool_destroy:200: broadcast workers to shut down
ras_server.c: threads_pool_default_routine:116: shut down [0x93d08700]
ras_server.c: threads_pool_default_routine:116: shut down [0x94d0a700]
ras_server.c: threads_pool_default_routine:116: shut down [0x94509700]ras_server.c: threads_pool_destroy:205: destroy worker id is 0:[94d0a700]

ras_server.c: threads_pool_destroy:205: destroy worker id is 1:[94509700]
ras_server.c: threads_pool_destroy:205: destroy worker id is 2:[93d08700]
ras_server.c: threads_pool_destroy:208: free workers
ras_server.c: threads_pool_destroy:211: free tasks

关键要点:

1、在启动前,预先创建好固定数目的工作线程,而不是动态创建,因为调用pthread_exit()之后,实际上系统并没有真正回收线程资源,而是必须调用pthread_join()才可以,所以会造成内存泄漏。

2、在启动前,预先创建好固定数目的任务书结构,并且循环利用,减少动态创建的时间消耗。

3、在提交任务书的时候,假如没有空闲的,需要等待1毫秒。任务书的数目与等待时长,往后可以根据实际应用做调整,并不会造成太大影响。

4、在任务书的执行顺序上,没有使用FIFO的方式,而是后进先出的方式。可能会造成一定程度困惑。主要是考虑队列的长度太长,添加到尾部,需要遍历所有,造成与任务书数目成正比的耗时。

5、目前代码中,预留任务书的数目是工作线程数目的10倍,可根据应用场合调整该值。

 

posted @ 2020-07-30 09:43  joyce3800  阅读(161)  评论(0编辑  收藏  举报