[代码实例][C]Linux实现线程池

【Linux】线程终结篇:线程池以及线程池的实现 什么是线程池呢?线程池一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。线程池的应用场景:1.需要大量的线程来完成任务,且完成任务的时间比较短。WEB服务器完成网页请求这样的务,使用线程池技术是非常合适的。 阅读详情

ThreadPool.h

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <stdbool.h>

#include <pthread.h>

struct ThreadJob
{
	void* (*CallbackFunction)(void *arg);	// 线程回调函数
	void * Arg;								// 回调函数参数
	struct ThreadJob * Next;
};

typedef struct
{
	int ThreadCount;					// 线程池中开启线程的个数
	int QueueMaxCount;					// 队列中最大ThreadJob的个数
	struct ThreadJob * JobQueueHead;	// 指向ThreadJob的头指针
	struct ThreadJob * JobQueueTail;	// 指向ThreadJob的尾指针
	pthread_t * Threads;				// 线程池中所有线程的pthread_t
	pthread_mutex_t Mutex;				// 互斥信号量
	pthread_cond_t QueueEmptyCond;		// 队列为空的条件变量
	pthread_cond_t QueueNotEmptyCond;	// 队列不为空的条件变量
	pthread_cond_t QueueNotFullCond;	// 队列不为满的条件变量
	int QueueCount;						// 队列当前的ThreadJob个数
	bool IsQueueClosed;					// 队列是否已经关闭
	bool IsPoolClosed;					// 线程池是否已经关闭
} ThreadPool;

/*
 * Function: ThreadPool_Init
 * Description: 初始化线程池。
 * Arguments:
 *	@threadCount: 线程池大小。
 *	@queueMaxCount: 线程池队列大小。
 * Return: 指向线程池的指针。
 */
ThreadPool * ThreadPool_Init(int threadCount, int queueMaxCount);

/*
 * Function: ThreadPool_AddJob
 * Description: 向线程池添加任务。
 * Arguments:
 *	@threadPool: 指向线程池的指针。
 *	@callbackFunction: 线程回调函数。
 *	@arg: 回调函数参数。
 * Return: null。
 */
void ThreadPool_AddJob(ThreadPool * threadPool, void * (*callbackFunction)(void * arg), void * arg);

/*
 * Function: ThreadPool_Destroy
 * Description: 销毁线程池。
 * Arguments:
 *	@threadPool: 指向线程池的指针。
 * Return: null。
 */
void ThreadPool_Destroy(ThreadPool * threadPool);

#endif

ThreadPool.c

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include <stdbool.h>

#include "ThreadPool.h"

static void * _function(void * arg)
{
	if(!arg)
	{
		fprintf(stderr, "[_function()] Argument 'arg' is invalid");
		exit(EXIT_FAILURE);
	}

	ThreadPool * threadPool = (ThreadPool *)arg;

	struct ThreadJob *threadJob = NULL;
	while (true)
	{
		pthread_mutex_lock(&(threadPool->Mutex));

		//队列为空时,就等待队列非空
		while (threadPool->QueueCount == 0 && !threadPool->IsPoolClosed)
			pthread_cond_wait(&(threadPool->QueueNotEmptyCond), &(threadPool->Mutex));
		
		//线程池关闭
		if (threadPool->IsPoolClosed)
		{
			pthread_mutex_unlock(&(threadPool->Mutex));
			pthread_exit(NULL);
		}

		threadPool->QueueCount--;
		threadJob = threadPool->JobQueueHead;
		if (threadPool->QueueCount == 0)
		{
			threadPool->JobQueueHead = NULL;
			threadPool->JobQueueTail = NULL;
		}
		else
			threadPool->JobQueueHead = threadJob->Next;

		// 若队列为空,就可以通知ThreadPool_Destroy函数,销毁线程函数
		if (threadPool->QueueCount == 0)
			pthread_cond_signal(&(threadPool->QueueEmptyCond));
		
		// 队列非满,就可以通知ThreadPool_AddJob函数,添加新任务
		if (threadPool->QueueCount == threadPool->QueueMaxCount - 1)
			pthread_cond_broadcast(&(threadPool->QueueNotFullCond));  
		
		pthread_mutex_unlock(&(threadPool->Mutex));
		
		// 线程真正要做的任务,回调函数的调用
		(*(threadJob->CallbackFunction))(threadJob->Arg);
		
		free(threadJob);
	}
}

ThreadPool * ThreadPool_Init(int threadCount, int queueMaxCount)
{
	ThreadPool * threadPool = NULL;

	threadPool = malloc(sizeof(ThreadPool));
	if (!threadPool)
	{
		perror("[ThreadPool_Init()] malloc");
		exit(EXIT_FAILURE);
	}

	threadPool->ThreadCount = threadCount;
	threadPool->QueueMaxCount = queueMaxCount;
	threadPool->QueueCount = 0;
	threadPool->JobQueueHead = NULL;
	threadPool->JobQueueTail = NULL;
		
	if (pthread_mutex_init(&(threadPool->Mutex), NULL))
	{
		perror("[ThreadPool_Init()] pthread_mutex_init");
		exit(EXIT_FAILURE);
	}
	if (pthread_cond_init(&(threadPool->QueueEmptyCond), NULL))
	{
		perror("[ThreadPool_Init()] pthread_mutex_init");
		exit(EXIT_FAILURE);
	}
	if (pthread_cond_init(&(threadPool->QueueNotEmptyCond), NULL))
	{
		perror("[ThreadPool_Init()] pthread_cond_init");
		exit(EXIT_FAILURE);
	}
	if (pthread_cond_init(&(threadPool->QueueNotFullCond), NULL))
	{
		perror("[ThreadPool_Init()] pthread_cond_init");
		exit(EXIT_FAILURE);
	}
		
	threadPool->Threads = malloc(sizeof(pthread_t) * threadCount);
	if (!threadPool->Threads)
	{
		perror("[ThreadPool_Init()] malloc");
		exit(EXIT_FAILURE);
	}

	threadPool->IsQueueClosed = false;
	threadPool->IsPoolClosed = false;
	for (int i = 0; i < threadPool->ThreadCount; ++i)
		pthread_create(&(threadPool->Threads[i]), NULL, _function, threadPool);
		
	return threadPool;
}

void ThreadPool_AddJob(ThreadPool * threadPool, void * (*callbackFunction)(void * arg), void * arg)
{
	if(!threadPool)
	{
		fprintf(stderr, "[ThreadPool_AddJob()] Argument 'threadPool' is invalid");
		exit(EXIT_FAILURE);
	}
	if(!callbackFunction)
	{
		fprintf(stderr, "[ThreadPool_AddJob()] Argument 'callbackFunction' is invalid");
		exit(EXIT_FAILURE);
	}

	pthread_mutex_lock(&(threadPool->Mutex));

	// 队列满的时候就等待
	while (threadPool->QueueCount == threadPool->QueueMaxCount
			&& !(threadPool->IsQueueClosed || threadPool->IsPoolClosed))
		pthread_cond_wait(&(threadPool->QueueNotFullCond), &(threadPool->Mutex));
	
	// 队列关闭或者线程池关闭就退出
	if (threadPool->IsQueueClosed || threadPool->IsPoolClosed)
	{
		fprintf(stderr, "[ThreadPool_AddJob()] ThreadPool or Queue has been closed");
		exit(EXIT_FAILURE);
	}

	struct ThreadJob * threadJob = malloc(sizeof(struct ThreadJob));
	if (!threadJob)
	{
		perror("[ThreadPool_AddJob()] malloc");
		exit(EXIT_FAILURE);
	}

	threadJob->CallbackFunction = callbackFunction;    
	threadJob->Arg = arg;
	threadJob->Next = NULL;
	
	if (threadPool->JobQueueHead == NULL)   
	{
		threadPool->JobQueueHead = threadJob;
		threadPool->JobQueueTail = threadJob;

		// 队列空的时候,有任务来时就通知线程池中的线程:队列非空
		pthread_cond_broadcast(&(threadPool->QueueNotEmptyCond));
	}
	else
	{
		threadPool->JobQueueTail->Next = threadJob;
		threadPool->JobQueueTail = threadJob;    
	}

	threadPool->QueueCount++;

	pthread_mutex_unlock(&(threadPool->Mutex));
}

void ThreadPool_Destroy(ThreadPool * threadPool)
{
	if(!threadPool)
	{
		fprintf(stderr, "[ThreadPool_AddJob()] Argument 'threadPool' is invalid");
		exit(EXIT_FAILURE);
	}

	pthread_mutex_lock(&(threadPool->Mutex));

	// 若线程池或队列已经关闭,则说明已发生内部错误
	if (threadPool->IsQueueClosed || threadPool->IsPoolClosed)
	{
		fprintf(stderr, "[ThreadPool_Destroy()] ThreadPool or Queue has been closed");
		exit(EXIT_FAILURE);
	}
	
	// 设置队列关闭
	threadPool->IsQueueClosed = true;
	// 等待队列为空
	while (threadPool->QueueCount != 0)
		pthread_cond_wait(&(threadPool->QueueEmptyCond), &(threadPool->Mutex));
	
	// 设置线程池关闭
	threadPool->IsPoolClosed = true;

	pthread_mutex_unlock(&(threadPool->Mutex));

	// 唤醒线程池中正在阻塞的线程
	pthread_cond_broadcast(&(threadPool->QueueNotEmptyCond));
	//唤醒添加任务的ThreadPool_AddJob函数
	pthread_cond_broadcast(&(threadPool->QueueNotFullCond));
	
	// 等待线程池的所有线程执行完毕
	for (int i = 0; i < threadPool->ThreadCount; ++i)
		pthread_join(threadPool->Threads[i], NULL);
	
	/* 清理相关资源 */
	pthread_mutex_destroy(&(threadPool->Mutex));
	pthread_cond_destroy(&(threadPool->QueueEmptyCond));
	pthread_cond_destroy(&(threadPool->QueueNotEmptyCond));
	pthread_cond_destroy(&(threadPool->QueueNotFullCond));
	
	free(threadPool->Threads);

	struct ThreadJob * p = NULL;
	while (threadPool->JobQueueHead != NULL)
	{
		p = threadPool->JobQueueHead;
		threadPool->JobQueueHead = p->Next;
		free(p);
	}

	free(threadPool);
}
Linux环境下的C语言线程池设计与实现 本文还有配套的精品资源,点击获取 简介:本文深入探讨了在Linux环境中,如何利用C语言和pthread库实现线程池技术以优化多任务处理程序性能。介绍了线程池的基本概念及其带来的效率提升,并详细阐述了pthread库关键函数以及线程池核心组件的设计。文章还解释了线程池的实现步骤,并通过 Cpool 项目实例分析展示了线程池内部机制及其在多线程编程中的应用。 ... 阅读详情

相关推荐

linux 实现一个简单的线程池及工作

linux 实现一个简单的线程池及工作 本实例演示了线程池的创建使用

【Linux】-- 线程池

一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。

weixin_64609308的博客 828

线程池实例(Linux)

比较完整的线程池实例代码,Linux系统下完美运行

【Linux】线程实例 | 简单线程池

今天来写一个简单版本的线程池more。

慕雪华年的博客 1239

线程池示例代码

Linux系统编程——线程池,相关教程链接如下: http://blog.youkuaiyun.com/tennysonsky/article/details/46490099

一个linux下C实现的线程池源码

一个linux下的c实现的线程池,其中包括线程池的创建、销毁、线程状态等操作。

< Linux > 多线程(线程池)

目录 1、线程池的概念 2、线程池的使用场景 3、线程池的代码实现

bit_zyx的博客 1133

永磁同步电机定子槽型设计实战:从梨形槽到矩形槽的NVH优化之路

本文深入探讨了永磁同步电机定子槽型设计在NVH优化中的关键作用,对比了梨形槽与矩形槽的性能差异。通过Ansys Maxwell仿真和实际案例,揭示了矩形槽在提升槽满率、降低电磁噪声方面的优势,并总结了五大设计黄金法则,为电机设计工程师提供了实用指导。

weixin_28740299的博客 494

Linux — 线程池及多线程结尾

线程池一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。

一个努力拼搏的人 637

PointNetLK实战:5步搞定点云配准(附ModelNet40数据集训练技巧)

本文提供了一份详细的PointNetLK实战指南,帮助读者在5步内掌握点云配准技术。文章以ModelNet40数据集为例,深入讲解了环境搭建、数据预处理、模型训练与调试等核心步骤,并分享了关键的训练技巧和调参策略,旨在让开发者快速实现并应用这一高效的深度学习配准方法。

wind6的博客 462

AI视频生成本地搭建图文详细过程

在自己的电脑上搭建一个AI,主要用于通过自己输入的关键字来自动生成视频文案,把视频文案自动生成视频,再自动给视频配音配字幕。

张小三的博客 4694

2020-09-13 Linux 线程池的原理及实现

参考:https://blog.youkuaiyun.com/lmh12506/article/details/7753952 /* 什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了。如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了。 下面是Linux系统下用C语言创建的一个线程池。线程池会维护一个任务链表(每个PthreadWorker结构就是一个任务)。 ...

llzhang_fly的博客 355

深信服技术认证“SCCA-C”划重点:信服云托管云

该认证包括云数据中心基础、云计算基础、云计算关键技术、云计算交付和运维体系、云计算技术商业应用、信服云托管云、深信服超融合HCI、深信服桌面云aDesk、深信服分布式存储EDS、深信服应用交付AD。学习并获得SCCA-C认证后,可以具备深信服产品功能原理与实践,能够根据业务需求,协助完成云产品方案落地与实施;能够根据业务需求,完成深信服云产品的部署和管理的基本工作。为帮助大家更加系统化地学习云计算知识,高效通过云计算工程师认证,深信服特推出“SCCA-C认证备考秘笈”,共十期内容。

sangfor_edu的博客 613

一个Linux下C线程池的实现

文章出处:http://hi.baidu.com/boahegcrmdghots/item/f3ca1a3c2d47fcc52e8ec2e1        什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了。如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要

韦编二绝 991

linux安装配置Mysql详细步骤

下载Mysql rpm包 官网下载:https://dev.mysql.com/downloads/mysql/ 如果你到了这里,本地应该有了如下四个rpm包: mysql-community-client-5.7.26-1.el6.x86_64.rpm mysql-community-common-5.7.26-1.el6.x86_64.rpm mysql-community-libs-5...

🏆 前端领域优质创作者 7万+

【Claude】API Error 通用错误:错误码含义与标准排查流程 bug报错已解决

Claude API 各类错误码速查与标准排查流程。

博客 8245

linux环境下c线程池详解

<br /><br />一、“知其然,不知其所以然”<br />因为工作需要,用到了线程池。用的并不是自己写的,而是人家实现的线程池(windows库文件),使用起来也挺简单。工作嘛,完成任务放在第一位,就没再对其深究,能用就好。<br /><br />二、“只知其一不知其二” <br />同样应为工作需要,程序需要从windows移植到linux下,线程池需要自己编写。于是在网上找资料。实现的源码一大片,方式风格各异,但就是没找到一个讲整个流程的,以及关键点。<br />了解到的资料大致如下:1、提前创建

roc1005的专栏 2120

LSTM 深度解析从原理推演到现代序列建模的演进

LSTM(Long Short-Term Memory,长短期记忆网络)是一种特殊的递归神经网络(RNN),它通过引入记忆单元(Cell State)来解决普通RNN在长序列数据处理中的梯度消失问题。LSTM可以在长时间的序列中捕捉依赖关系,是一种非常适合处理时间序列、自然语言处理、语音识别等任务的深度学习模型。在LSTM中,记忆单元(Cell State)是一个贯穿整个序列的数据通道,用于存储和传递关键信息。记忆单元在LSTM的时间步之间保持信息的持久性,可以看作是一个长期记忆的“容器”。

hello.reader 3万+

Linux C实现线程池

Linux C语言 线程池的实现 链表操作,锁 条件变量使用

C++ 开发者的博客 1752

【ACP】2025-最新-疑难题解析- 练习二汇总

全球加速是优化公网访问的,负载均衡是分发流量的,公网 NAT 网关是处理公网 IP 的,高速通道是建私网连接但不直接提供固定私网地址功能。C 是客户端加密方式,D 是 ECS 云盘加密,都不属于 OSS 服务器端加密。某企业想使用云服务器 ECS + 负载均衡 SLB + 弹性伸缩 (Auto Scaling) 的架构搭建一个企业级门户网站,技术负责人对于负载均衡和弹性伸缩配合使用没有经验,于是将他理解的两种产品配合使用的一些技术细节列成了一个表单,并请作为架构师的您帮他做一下鉴别,以下哪些项是正确的?

jundao1997的专栏 296

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Linux下C语言线程池实现

0x00前言 文章中的文字可能存在语法错误以及标点错误,请谅解; 如果在文章中发现代码错误或其它问题请告知,感谢! 0x01线程池工作原理简介 线程池是一个比较抽象的概念,其包含任务队列,多个线程,管理线程等。 在应用程序启动后,线程池首先会创建一定数量的线程,放入到空闲队列,并让所有线程处在阻塞状态 。当有任务发生后,线程池会选择一个空闲的线程,将任务传入到该线程运行。执行完任务之后,线程并不退...

C/C++攻城狮 1342

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

linux C 线程池

1. 总结理解 线程池的是什么? 线程池就好比水龙头的水流入一个较大的水池,当需要水的时候,5个人挑着扁担,每个人同时可以去打10桶水(各自打各自的2通水,互不影响),然后挑着就走。如果没有水池,那么每个人都需要在从水龙头上接自己的2桶水,谁先到水就先打水,这样打水的效率极低,5个人都需要排队打10桶水。 所以:线程池,顾名思义就是由多个线程组成的“水池”,当有任务需要执行时,由空闲线程进行处理,若没有任务,则线程处于休眠等待的状态。 什么时候需要创建线程池呢?(为什么要使用线程池?) 如果一个应

llzhang_fly的博客 1292

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Linux下C语言实现线程池

前面看完C++实现线程池之后,接下来我们看看C语言如何实现线程池,原理是类似的,C++主要是使用线程的类Thread,而C语言的实现主要是调用Linux中的系统函数。 1、线程池的具体的实现代码如下: 文件thread_pool.cpp: #include<stdio.h> #include<stdlib.h> #include<unistd.h...

蓬莱道人的博客 2105
上一篇: [代码实例][C]Linux多线程编程示例
下一篇: [编程语言][C]宏函数之坑
cloudblaze
博客等级 码龄17年 81粉丝 125原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值