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日

相关文章

  • 详解c++良好的编程习惯与编程要点

    详解C++良好的编程习惯与编程要点 C++是一门广泛使用的编程语言,它的语法和特性非常丰富,同时也具有很高的灵活性。但是,如果我们没有遵循一些良好的编程习惯和编程要点,将会使我们的代码难以阅读和维护。下面我们将详细讲解C++良好的编程习惯与编程要点。 1. 命名规范 良好的命名规范是写出易读易懂的代码的关键。我们应该遵循以下命名规范: 变量名和函数名应该是有…

    C 2023年5月22日
    00
  • MFC程序对文件的处理方法

    MFC程序对文件的处理方法主要包括文件的创建、读取、写入和关闭操作。下面将针对每一种操作进行详细讲解。 文件的创建 要在MFC程序中创建一个新文件,可以使用CFile类的Open方法,该方法会打开指定的文件并返回一个CFile对象,可以通过该对象对文件进行操作。 示例1:创建一个名为”test.txt”的文本文件 CFile file; if (file.O…

    C 2023年5月23日
    00
  • 如何在c++中实现字符串分割函数split详解

    如何在C++中实现字符串分割函数split详解 简介 字符串分割是比较常见的字符串处理方式之一,常用于将一个字符串按照特定的分隔符分割成若干个子串。在C++中,实现字符串分割可以通过一些STL容器和标准库函数来完成。 实现 方法一:使用stringstream stringstream是C++ STL库中用来进行字符串流处理的一个类。使用这个类可以将一个字符…

    C 2023年5月23日
    00
  • C++实现寝室卫生管理系统

    C++实现寝室卫生管理系统 1. 系统需求分析 在实现寝室卫生管理系统时,我们需要明确系统的需求和功能。一个基本的寝室卫生管理系统应该包括以下功能: 管理员登录:管理员需要进行身份验证,才能进行管理操作; 学生信息录入:管理员可以添加、修改、删除学生信息; 寝室卫生评分:管理员需要对寝室进行卫生评分,并记录下评分结果; 查询寝室卫生:学生可以通过系统查询自己…

    C 2023年5月23日
    00
  • C++控制台实现密码管理系统

    为了编写C++控制台实现密码管理系统,我们需要遵循以下步骤: 步骤1:设计数据结构 设计数据结构是密码管理系统的第一步,我们需要确定各种密码信息的存储方式。我们可以选择使用结构体、类或数组来存储不同的用户信息。 例如: struct Password{ char username[15]; char password[15]; char descriptio…

    C 2023年5月23日
    00
  • Android中各种Time API详细

    Android中各种Time API详细攻略 在Android开发中,时间是一个非常基础的概念,也是涉及到很多核心领域(如UI事件处理、数据同步等)的重要因素。本文将详细介绍在Android中使用各种时间API的方法。 System.currentTimeMillis() System.currentTimeMillis()方法返回当前系统时间(自1970年…

    C 2023年5月22日
    00
  • asp.net下将纯真IP数据导入数据库中的代码

    下面是详细讲解“asp.net下将纯真IP数据导入数据库中的代码”的完整攻略: 前置要求 在开始编写代码之前需先准备好以下内容: 纯真IP数据库,可以到官网下载; Visual Studio开发环境; SQL Server数据库。 导入纯真IP数据库 下载纯真IP数据库,并将其解压到本地硬盘; 在SQL Server中创建一个新的数据库,例如命名为ipdb;…

    C 2023年5月23日
    00
  • 详解php与ethereum客户端交互

    详解php与ethereum客户端交互 概述 Ethereum是一种基于区块链的分布式应用程序平台,它提供了以太币(Ether)作为加密数字货币的基础,并允许在以太坊上构建智能合约。 PHP是一种流行的Web编程语言,通常用于构建Web应用程序。 本文将介绍如何使用PHP与Ethereum客户端进行交互,以便于实现以太坊智能合约的部署和调用。 安装 在PHP…

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