C/C++ 原生API实现线程池的方法

C/C++原生API实现线程池,可以通过以下步骤来实现:

第一步:定义线程池结构体

线程池结构体的定义通常包含以下几个成员:

  • 线程池中线程的数量:通过这个成员可以控制线程池中线程的数量
  • 任务队列:用来存储要执行的任务
  • 线程池是否正在运行:通过这个成员可以控制是否继续执行任务

定义如下:

typedef struct threadpool {
    int thread_num; // 线程池线程数量
    int queue_size; // 任务队列长度
    pthread_t *threads; // 线程数组
    pthread_mutex_t lock; // 互斥锁
    pthread_cond_t notify; // 条件变量
    task *task_queue; // 任务队列
    int queue_head; // 任务队列头
    int queue_tail; // 任务队列尾
    int queue_count; // 任务队列中任务数量
    int shutdown; // 线程池是否关闭
} threadpool;

第二步:实现任务结构体

任务结构体存储要执行的任务,其中包含以下成员:

  • 任务函数指针:用来存储要执行的任务函数
  • 任务参数:执行任务所需的参数

定义如下:

typedef struct {
    void (*function)(void *arg); // 任务函数指针
    void *arg; // 任务参数
} task;

第三步:初始化线程池

线程池的初始化包含以下步骤:

  • 初始化锁和条件变量
  • 创建线程数组
  • 创建任务队列
  • 启动线程

具体代码如下:

threadpool *threadpool_create(int thread_num, int queue_size) 
{
    threadpool *pool;
    int i;

    // 判断输入参数是否合法
    if ((pool = (threadpool *)malloc(sizeof(threadpool))) == NULL) 
    {
        goto err;
    }

    // 初始化线程池变量
    pool->thread_num = 0;
    pool->queue_size = queue_size;
    pool->queue_head = 0;
    pool->queue_tail = 0;
    pool->queue_count = 0;
    pool->shutdown = 0;

    // 创建线程数组
    pool->threads = (pthread_t *)malloc(thread_num * sizeof(pthread_t));
    if (pool->threads == NULL) 
    {
        goto err;
    }

    // 创建任务队列
    pool->task_queue = (task *)malloc(queue_size * sizeof(task));
    if (pool->task_queue == NULL) 
    {
        goto err;
    }

    // 初始化锁和条件变量
    if ((pthread_mutex_init(&(pool->lock), NULL) != 0) || 
        (pthread_cond_init(&(pool->notify), NULL) != 0))
    {
        goto err;
    }

    // 创建线程
    for (i = 0; i < thread_num; i++) 
    {
        if (pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void*)pool) != 0)
        {
            threadpool_destroy(pool, 0);
            return NULL;
        }
        pool->thread_num++;
    }

    return pool;

err:
    if (pool) 
    {
        threadpool_destroy(pool, 0);
    }
    return NULL;
}

第四步:实现任务添加函数

任务添加函数用来向任务队列中添加任务。实现步骤如下:

  • 首先需要获得线程池的锁
  • 添加任务到任务队列中
  • 通知正在等待任务的线程有任务可供执行

具体代码如下:

int threadpool_add(threadpool *pool, void (*function)(void *), void *arg)
{
    int err = 0;
    int next_tail = 0;

    // 获得线程池的锁
    if (pthread_mutex_lock(&(pool->lock)) != 0) 
    {
        return THREADPOOL_LOCK_FAILURE;
    }

    next_tail = (pool->queue_tail + 1) % pool->queue_size;

    do 
    {
        // 判断任务队列是否已满
        if (pool->queue_count == pool->queue_size) 
        {
            err = THREADPOOL_QUEUE_FULL;
            break;
        }

        // 添加任务到任务队列中
        pool->task_queue[pool->queue_tail].function = function;
        pool->task_queue[pool->queue_tail].arg = arg;
        pool->queue_tail = next_tail;
        pool->queue_count += 1;

        // 通知正在等待任务的线程有任务可供执行
        if (pthread_cond_signal(&(pool->notify)) != 0) 
        {
            err = THREADPOOL_LOCK_FAILURE;
            break;
        }

    } while (0);

    // 释放线程池的锁
    if (pthread_mutex_unlock(&pool->lock) != 0) 
    {
        err = THREADPOOL_LOCK_FAILURE;
    }

    return err;
}

第五步:实现线程函数

线程函数用来从任务队列中取出任务并执行。线程函数应该不断地从任务队列中取出任务执行,或者等待新的任务到来执行。具体代码如下:

void *threadpool_thread(void *threadpool) 
{
    threadpool *pool = (threadpool *)threadpool;
    task task;

    for (;;) 
    {
        // 获得线程池的锁
        pthread_mutex_lock(&(pool->lock));

        // 循环直到有任务可供执行
        while ((pool->queue_count == 0) && (!pool->shutdown)) 
        {
            pthread_cond_wait(&(pool->notify), &(pool->lock));
        }

        if ((pool->shutdown) && (pool->queue_count == 0)) 
        {
            break;
        }

        // 取出任务并执行
        task.function = pool->task_queue[pool->queue_head].function;
        task.arg = pool->task_queue[pool->queue_head].arg;
        pool->queue_head = (pool->queue_head + 1) % pool->queue_size;
        pool->queue_count -= 1;

        // 释放线程池的锁
        pthread_mutex_unlock(&(pool->lock));

        (*(task.function))(task.arg); // 执行任务
    }

    // 销毁线程池
    pthread_mutex_unlock(&(pool->lock));
    pthread_exit(NULL);
    return (NULL);
}

第六步:实现线程池销毁函数

线程池销毁函数用来销毁线程池。销毁线程池时,应该将线程池标记为关闭状态,通知所有等待任务的线程线程池已关闭,然后等待所有线程完成任务并退出。具体代码如下:

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

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

    // 获得线程池的锁
    if (pthread_mutex_lock(&(pool->lock)) != 0) 
    {
        return THREADPOOL_LOCK_FAILURE;
    }

    // 标记线程池为关闭状态
    pool->shutdown = 1;

    // 发送通知给所有等待任务的线程
    if ((pthread_cond_broadcast(&(pool->notify)) != 0) || 
        (pthread_mutex_unlock(&(pool->lock)) != 0)) 
    {
        err = THREADPOOL_LOCK_FAILURE;
        goto err;
    }

    // 等待所有线程完成任务并退出
    for (i = 0; i < pool->thread_num; i++) 
    {
        if (pthread_join(pool->threads[i], NULL) != 0) 
        {
            err = THREADPOOL_THREAD_FAILURE;
        }
    }

    if (!flags) 
    {
        free(pool->threads);
        free(pool->task_queue);
        pthread_mutex_destroy(&(pool->lock));
        pthread_cond_destroy(&(pool->notify));
    }
    free(pool);

    return err;

err:
    pthread_mutex_unlock(&(pool->lock));
    return err;
}

下面是一个示例代码:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include "threadpool.h"

#define THREAD 4
#define QUEUE  100

typedef struct {
    int a;
    int b;
} test_task_t;

void task_test(void *arg)
{
    test_task_t *task = (test_task_t *)arg;
    int i, sum = 0;
    for (i = 0; i < task->a; i++) 
    {
        sum += task->b;
    }
    printf("sum=%d\n", sum);
}

int main(int argc, char **argv)
{   
    int a[4] = {1, 2, 3, 4};
    int b[4] = {1, 10, 100, 1000};
    int i;

    threadpool *pool;
    test_task_t task[4];

    pool = threadpool_create(THREAD, QUEUE);

    for (i = 0; i < 4; i++) 
    {
        task[i].a = a[i];
        task[i].b = b[i];
        threadpool_add(pool, task_test, &task[i]);
    }

    sleep(5);
    threadpool_destroy(pool, 0);

    return 0;
} 

在这个示例中,首先定义了一个test_task_t结构体存储任务参数a和b,然后创建了一个线程池,向线程池中添加4个任务,每个任务都是对test_task_t结构体进行处理。最后,等待5秒钟后销毁线程池。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C/C++ 原生API实现线程池的方法 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • 基于opencv的selenium滑动验证码的实现

    首先需要明确的是,基于opencv的selenium滑动验证码实现主要考察的是图像识别和模拟鼠标操作的能力。下面是详细的攻略: 步骤一:收集参考图片和滑块图片 首先需要在浏览器中打开目标网站,然后找到需要滑动验证码的页面。在这个页面中,需要使用开发者工具的元素选择器找到验证码区域的HTML元素,然后通过selenium的接口获取到该元素的截图,作为参考图片。…

    C 2023年5月23日
    00
  • 天天飞车C级赛车奥赛德属性解析 天天飞车奥赛德怎么样

    天天飞车C级赛车奥赛德属性解析 奥赛德的基本属性 奥赛德是一台拥有强大抓地力和过弯性能的赛车,它的基本属性为: 速度:5 加速:4 操控:7 平稳:5 强度:5 其中,操控是奥赛德最出色的一项属性,它让赛手们能够更快地穿越弯道,提高比赛的成绩。 奥赛德的细节属性 奥赛德的细节属性包括: 重量:1350kg 长度:4663mm 宽度:1892mm 车高:142…

    C 2023年5月23日
    00
  • C语言实现小型工资管理系统

    下面我会详细讲解一下“C语言实现小型工资管理系统”的完整攻略。 1. 确定功能需求 首先需要确定工资管理系统的具体功能需求,例如: 添加员工信息 修改员工信息 查询员工信息 删除员工信息 计算员工工资 2. 建立数据存储模型 其次需要建立数据存储模型,决定使用何种数据结构来存储员工信息。通常可以使用结构体来定义员工信息,例如: struct Employee…

    C 2023年5月23日
    00
  • C语言超详细讲解栈的实现及代码

    C语言超详细讲解栈的实现及代码 什么是栈? 栈(Stack)是计算机中的一种数据结构,也是一种线性结构。它只允许在特定一端进行插入和删除操作,即在栈顶进行操作。栈的特点是后进先出(LIFO,Last In First Out),即在栈顶进入元素,在栈顶取出元素。 栈的实现 栈的实现可以用数组(array)或链表(linked list)来实现。其中,一般使用…

    C 2023年5月23日
    00
  • 详解C++程序中定义struct结构体的方法

    下面我将详细讲解如何在C++程序中定义struct结构体。 1. 概述 在C++中,struct是一种用户自定义的数据类型,它可以将多个不同类型的数据成员组合在一起,形成一个数据结构。在C++中,我们可以使用struct关键字来定义一个结构体,然后在程序中实例化一个结构体对象,可以使用结构体对象来访问结构体中的数据成员,从而完成对数据的处理。 2. 定义结构…

    C 2023年5月30日
    00
  • C语言实现扫雷程序

    为了更好地阐述如何实现扫雷程序,我将按照以下步骤给出完整攻略: 1. 设计游戏界面 首先,我们需要一个游戏界面,在游戏界面中需要有一个地图、雷区和计分板。可以使用图形化界面库如GTK、QT等来完成界面的搭建,也可以使用控制台界面(命令行界面)以字符方式来实现。在这里,我们将以控制台界面为例进行演示。 在终端中,使用字符来显示方格和数字,用字母来代表是否被扫。…

    C 2023年5月23日
    00
  • C语言教程之数组详解

    C语言教程之数组详解 数组概述 数组是一组相同类型数据的集合,它们按照一定的先后顺序排列,每个数组元素可以通过一个下标访问。 在C语言中,数组元素是按照线性顺序存储在内存中的,数组下标从0开始,可以是整数、字符、枚举类型。 声明数组 在C语言中,可以使用以下方式来声明数组: type arrayName[arraySize]; 其中type为数组元素类型,a…

    C 2023年5月23日
    00
  • C语言职工管理系统设计

    C语言职工管理系统设计攻略 目录 概述 界面设计 功能设计 代码实现 示例说明 总结 1. 概述 C语言职工管理系统设计是一个基于控制台的应用程序,旨在设计一个能够管理职工信息的管理系统,方便管理员有效地管理职工信息。 本系统的主要功能包括:添加职工、显示职工、删除职工、修改职工、查找职工、排序职工等。 2. 界面设计 首先,需要针对系统的功能进行界面设计,…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部