linux之线程池

1. 简介

• 线程池是一种用于管理和重用多个线程的设计模式 。它通过维护一个线程池(线程的集合),可以有效地处理并发任务而无需每次都创建和销毁线程 。这种方法可以减少线程创建和销毁的开销,提高性能和资源利用率。 提高响应速度,任务来了直接交给空闲线程执行,无需等待线程创建。

2. Glib的工作流程

• 线程池创建:首先创建一个线程池,指定任务函数和其他参数 。线程池会创建一定数量的线程,这些线程进入等待状态,准备执行任务,或在提交任务后才创建线程(取决于配置)。线程池中的所有线程执行的都是同一个任务函数。

• 任务队列:线程池维护一个任务队列。当我们向线程池提交任务时,任务会被放入这个队列中实际上,放入任务队列 的是 我们在提交任务时传递的任务数据。

• 线程执行任务:线程池中的线程从任务队列中取出任务数据,然后调用任务函数,执行任务。执行完成后,线程不会退出,而是继续从任务队列中取下一个任务执行。如果没有待执行的任务,线程通常在等待一段时间后被回收(取决于具体的配置)。

3. 相关函数

3.1 GFunc

cpp 复制代码
// 此处的 data 是在启动任务时,传递给每个任务的,而 user_data 是在创建线程池时传入的共享数据,对于每个任务都是一样的 
typedef void (*GFunc)(gpointer data, gpointer user_data);

3.2 g_thread_pool_new

cpp 复制代码
/** 
* @brief 创建新的线程池 
* 
* @param func 池中线程执行的函数 
* @param user_data 传递给 func 的数据,可以为 NULL,这里的 user_data 最终会被存储在 GThreadPool 结构体的 user_data 属性中 
* @param max_threads 线程池容量,即当前线程池中可以同时运行的线程数。-1 表示没有限制 
* @param exclusive 独占标记位。决定当前的线程池独占所有的线程 还是与其它线程池共享这些线程。取值可以是 TRUE 或 FALSE 
* TRUE:立即启动数量为 max_threads 的线程,且启动的线程只能被当前线程池使用 
* FALSE:只有在需要时,即需要执行任务时才创建线程,且线程可以被多个非独享资源的线程池共用 
* @param error 用于报告错误信息,可以是 NULL,表示忽略错误 
* @return GThreadPool* 线程池实例指针。无论是否发生错误,都会返回有效的线程池 
*/ 
GThreadPool *g_thread_pool_new( 
	GFunc func, 
	gpointer user_data, 
	gint max_threads, 
	gboolean exclusive, 
GError **error);

3.3 g_thread_pool_push

cpp 复制代码
/** 
* @brief 向 pool 指向的线程池实例添加数据,这一行为实际上会向任务队列添加新的任务。当存在可用线程时任务立即执行,否则任务数据会一直待在队列中,直至腾出可用线程执行任务 
* 
* @param pool 指向线程池实例的指针 
* @param data 传递给每个任务的独享数据 
* @param error 错误信息 
* @return gboolean 成功返回 TRUE,失败返回 FALSE 
*/ 
gboolean g_thread_pool_push( 
	GThreadPool *pool, 
	gpointer data, 
GError **error);

3.4 g_thread_pool_free

cpp 复制代码
/** 
* @brief 释放为 pool 指向的线程池分配的所有资源 
* 
* @param pool 线程池指针 
* @param immediate 是否立即释放线程池 
* TRUE:立即释放所有资源,未处理的数据不被处理 
* FALSE:在最后一个任务执行完毕之前,线程池不会被释放 
* 需要注意的是:执行任务时,线程池的任何一个线程都不会被打断。无论这个参数是何取值,都可以保证至少线程池释放前正在运行的线程可以完成它们的任务。 
* @param wait_ 当前函数是否阻塞等待 所有任务完成 
* TRUE:所有需要处理的任务执行完毕当前函数才会返回 
* FALSE:当前函数立即返回 
*/ 
void g_thread_pool_free ( 
	GThreadPool* pool, 
	gboolean immediate, 
	gboolean wait_ 
);

3.5 例子

cpp 复制代码
#include <glib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>


void task(gpointer data,gpointer user_data){
    int tmp = *((int *)data);//每个任务独享的数据。
    free(data);
    printf("任务%d开始执行\n",tmp);
    sleep(tmp);
    printf("任务%d执行结束\n",tmp);
}

int main(int argc, char const *argv[])
{
    //创建线程池
    GThreadPool * gtp = g_thread_pool_new(task,NULL,5,TRUE,NULL);

    //提交任务10个
    for (size_t i = 0; i < 10; i++)
    {
        int * tmp = malloc(sizeof(int));
        *tmp =  i + 1;
        g_thread_pool_push(gtp,tmp,NULL);
    }
    
    //释放线程池
    g_thread_pool_free(gtp,FALSE,TRUE);
    printf("所有任务都执行完成了\n");
    return 0;
}

• 结果,如图:

相关推荐
海盗12342 分钟前
.NET编码规范03-C#命名规范大全
linux·服务器·.net
WZF-Sang5 分钟前
TCP和UDP协议
linux·服务器·网络·c++·学习·tcp/ip·udp
做个文艺程序员10 分钟前
Linux第11篇:存储管理——磁盘分区、LVM 与文件系统
linux·运维·服务器
天空'之城20 分钟前
Linux 系统编程 14:Reactor 反应堆模式
linux·开发语言·网络编程·reactor 反应堆模式
法号:行颠30 分钟前
《Linux内核源码全景解读:从上电到用户态》之 目录
linux
mounter6253 小时前
深入解析 RDMA 中的 Address Handler (AH) 缓存:AWS EFA 驱动的硬件演进与软件复用艺术
linux·kernel·rdma·hashtable·hash table·address handle
笑锝没心没肺10 小时前
fail2ban工具安装配置及使用
linux·运维·服务器
大卡片12 小时前
linux内核驱动开发
linux·运维·驱动开发
心心喵13 小时前
[linux] nohup和pm2的区别 进程保活
linux·运维·服务器
醉熏的石头14 小时前
Ubuntu 中的编程语言(中)
linux·ubuntu·scala