/*解析:这段代码创建了三个线程,10个任务。线程池的结构是CThread_pool,任务的结构是worker,他们都是一个连表。
程序先用pool_init创建拉三个线程。然后每个线程执行函数thread_routine。thread_routine在运行到pthread_cond_wait(&(pool->queue_ready),&(pool->queue_lock));时,等待共享变量被激活;
当添加任务的函数pool_add_worker添加拉任务之后,运行到pthread_cond_signal(&(pool->queue_ready));激活等待的线程。它告诉线程,有任务拉,可以运行拉。然后thread_routine运行pthread_cond_wait(&(pool->queue_ready),&(pool->queue_lock));之后的代码。
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
/*
*线程池里所有运行和等待的任务都是一个CThread_worker;由于所有任务都在连表里,所以是个连表结构
*/
typedef struct worker
{
/*回调函数,任务运行时会调用此函数,注意也可声明成其他形式*/
void *(*process)(void *arg);
void *arg;
struct worker *next;
}CThread_worker;
/**线程池结构*/
typedef struct
{
pthread_mutex_t queue_lock;
pthread_cond_t queue_ready;
/*连表结构,线程池中的所有等待任务*/
CThread_worker *queue_head;
/*是否销毁线程池*/
int shutdown;
pthread_t *threadid;
/*线程池中允许的活动线程数目*/
int max_thread_num;
/*当前等待列队的任务数目*/
int cur_queue_size;
}CThread_pool;
int pool_add_worker(void*(*process)(void *arg),void *arg);
void *thread_routine(void *arg);
static CThread_pool *pool=NULL;//=(CThread_pool *)NULL;
void pool_init(int max_thread_num)
{
pool=(CThread_pool*)malloc(sizeof(CThread_pool));
pthread_mutex_init(&(pool->queue_lock),NULL);
//初始化一个条件变量,他的第二个条件变量可以用来定义这个变量是在进程间使用还是进程内各个线程间使用。
pthread_cond_init(&(pool->queue_ready),NULL);
pool->queue_head=NULL;
pool->max_thread_num=max_thread_num;
pool->cur_queue_size=0;
pool->shutdown=0;
pool->threadid=(pthread_t*)malloc(max_thread_num*sizeof(pthread_t));
int i=0;
for(i=0;i<max_thread_num;i++)
{
pthread_create(&(pool->threadid[i]),NULL,thread_routine,NULL);
}
}
/*向线程池中添加任物*/
int pool_add_worker(void *(*process)(void *arg),void *arg)
{
printf("pool_add_worker:/n");
/*构造一个新任务*/
CThread_worker *newworker=(CThread_worker*)malloc(sizeof(CThread_worker));
newworker->process=process;
newworker->arg=arg;
newworker->next=NULL;/*dont forget set it to null*/
pthread_mutex_lock(&(pool->queue_lock));
/*将任务加入到等待列队中*/
CThread_worker* member=pool->queue_head;
if(member!=NULL)
{
while(member->next!=NULL)
member = member->next;
member->next=newworker;
}
else
{
pool->queue_head=newworker;
}
assert(pool->queue_head!=NULL);
pool->cur_queue_size++;
pthread_mutex_unlock(&(pool->queue_lock));
/*好了,等待列队中有任务拉,唤醒一个等待线程;注意如果所有线程都在忙碌,这句话没有任何作用*/
pthread_cond_signal(&(pool->queue_ready));
return 0;
}
/*销毁线程池,等待列队中的任务不会再被执行拉。但是正在运行的线程会一直把任务运行完后再推出*/
int pool_destory()
{
if(pool->shutdown)
return -1;/*防止两次调用*/
pool->shutdown=1;
/*唤醒所有等待的线程,线程池要销毁拉*/
pthread_cond_broadcast(&(pool->queue_ready));
/*阻塞等待线程退出,否则就成拉僵尸拉*/
int i;
for(i=0;i<pool->max_thread_num;i++)
{
printf("pool_destroy: thread %d/n",i);
pthread_join(pool->threadid[i],NULL);//用来等待线程结束,这事一个阻塞函数
}
free(pool->threadid);
/*销毁等待列队*/
CThread_worker *head=NULL;
while(pool->queue_head!=NULL)
{
head=pool->queue_head;
pool->queue_head=pool->queue_head->next;
free(head);
}
/*条件变量和互斥变量也别忘了销毁*/
pthread_mutex_destroy(&(pool->queue_lock));
pthread_cond_destroy(&(pool->queue_ready));
free(pool);
/*销毁后指针置NULL,good*/
pool=NULL;
return 0;
}
void *thread_routine(void *arg)
{
printf("starting thread 0x%ld/n",pthread_self());
while(1)
{
pthread_mutex_lock(&(pool->queue_lock));
/*如果等待列队为0并且不销毁线程池,则处于阻塞状态;*注意pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/
while((pool->cur_queue_size==0)&&(!pool->shutdown))
{
printf("thread 0x%ld is waiting/n",pthread_self());
pthread_cond_wait(&(pool->queue_ready),&(pool->queue_lock));
}
/*线程池要销毁拉*/
if(pool->shutdown)
{
/*遇到break,continue, return等语句跳转,别忘记现解锁*/
pthread_mutex_unlock(&(pool->queue_lock));
printf("thread 0x%x will exit/n",pthread_self());
pthread_exit(NULL);
}
printf("thread 0x%ld is starting to work/n",pthread_self());
/*assert 是调试的好帮手*/
assert(pool->cur_queue_size!=0);
assert(pool->queue_head!=NULL);
/*等待队列长度减去1,并取出联表中的头元素*/
pool->cur_queue_size--;
CThread_worker *worker=pool->queue_head;
pool->queue_head=worker->next;
pthread_mutex_unlock(&(pool->queue_lock));
/*调用回调函数,执行任务*/
printf("************/n");
(*(worker->process))(worker->arg);
free(worker);
worker=NULL;
}
/*这一句应该是不可达的*/
pthread_exit(NULL);
}
/*测试代码*/
void * myprocess(void *arg)
{
printf("threadid is 0x%ld,working on task %d/n",pthread_self(),*(int*)arg);
sleep(1);/*休息一秒,延长任务的执行时间*/
return NULL;
}
int main(int argc,char** argv)
{
pool_init(3);/*线程池中最多三个活动线程*/
/*连续向池中投入10个任务*/
int *workingnum = (int*)malloc(sizeof(int)*10);
int i;
for(i=0;i<10;i++)
{
printf("main:while %d/n",i);
workingnum[i]=i;
pool_add_worker(myprocess,&workingnum[i]);
}
printf("/nSleep 5 sec to wait all thread work!/n ");
/*等待所有任务完成*/
sleep(5);
/*销毁线程池*/
printf("/n销毁线程池/n");
pool_destory();
free(workingnum);
return 0;
}
/*输出*/
/*
starting thread 0x140353963693824
starting thread 0x140353955301120
main:while 0
starting thread 0x140353946908416
thread 0x140353963693824 is waiting
pool_add_worker:
main:while 1
pool_add_worker:
thread 0x140353963693824 is starting to work
************
threadid is 0x140353963693824,working on task 0
thread 0x140353946908416 is waiting
thread 0x140353955301120 is starting to work
************
threadid is 0x140353955301120,working on task 1
main:while 2
pool_add_worker:
thread 0x140353946908416 is waiting
main:while 3
pool_add_worker:
thread 0x140353946908416 is starting to work
************
threadid is 0x140353946908416,working on task 2
main:while 4
pool_add_worker:
main:while 5
pool_add_worker:
main:while 6
pool_add_worker:
main:while 7
pool_add_worker:
main:while 8
pool_add_worker:
main:while 9
pool_add_worker:
Sleep 5 sec to wait all thread work!
thread 0x140353963693824 is starting to work
************
threadid is 0x140353963693824,working on task 3
thread 0x140353955301120 is starting to work
************
thread 0x140353946908416 is starting to work
************
threadid is 0x140353946908416,working on task 5
threadid is 0x140353955301120,working on task 4
thread 0x140353963693824 is starting to work
************
threadid is 0x140353963693824,working on task 6
thread 0x140353946908416 is starting to work
************
thread 0x140353955301120 is starting to work
************
threadid is 0x140353955301120,working on task 8
threadid is 0x140353946908416,working on task 7
thread 0x140353963693824 is starting to work
************
threadid is 0x140353963693824,working on task 9
thread 0x140353946908416 is waiting
thread 0x140353955301120 is waiting
thread 0x140353963693824 is waiting
销毁线程池
pool_destroy: thread 0
thread 0xb325f700 will exit
thread 0xb3a60700 will exit
thread 0xb4261700 will exit
pool_destroy: thread 1
pool_destroy: thread 2
*/
相关推荐
ST MCSDK V6.2.0实战:手把手教你配置HSO-ST观测器,体验500ms收敛的电机无感控制
本文详细介绍了ST MCSDK V6.2.0中HSO-ST观测器的配置方法,实现500ms内电流收敛的无感电机控制。从环境搭建、核心参数解析到无感启动优化,提供实战技巧和性能调优策略,帮助开发者快速掌握高效电机控制技术。
< Linux > 多线程(线程池)
目录 1、线程池的概念 2、线程池的使用场景 3、线程池的代码实现
给硬件工程师的UCIe软件配置入门:从寄存器表到实战调试,一篇讲透
本文为硬件工程师提供UCIe软件配置的全面指南,从寄存器表解析到实战调试技巧,涵盖链路训练、错误排查等关键环节。通过详细代码示例和分层诊断法,帮助工程师快速掌握UCIe寄存器访问机制,提升异构集成开发效率。
条件变量和线程池
条件变量 应用场景:生产者和消费者的问题,是线程同步的一种手段。 必要性:为了实现等待某个资源,让线程休眠。提高运行效率 int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict m
上位机1000条/秒数据不丢不卡:SQLite持久化队列最优方案实战
在上位机每秒1000条、1MB数据的场景下,SQLite做持久化队列是最优解可靠性拉满,ACID事务+WAL模式保证绝对不丢数据;性能完全够用,优化后每秒几千条没问题;轻量无依赖,只有一个.db文件;C#/.NET原生支持,代码简单易维护。只要按照上面的优化点和代码实现,完全能满足工业现场的需求,不用再担心数据丢失、存储卡采集的问题。
把浮点数这件小事讲清楚:ABAP 7.51 里 Open SQL 与 ABAP CDS 的 FLTP 新玩法与避坑指南
ABAP浮点数计算的风险与应对 摘要:ABAP项目中的浮点数(FLTP)在跨平台计算时存在误差风险,同一逻辑在不同数据库平台可能产生细微差异。ABAP 7.51新增了两项关键能力:1)Open SQL和ABAP CDS中可为AVG函数指定结果类型,避免默认返回FLTP;2)ABAP CDS提供FLTP_TO_DEC转换函数。但需注意这些转换仍可能存在平台相关差异,且FLTP_TO_DEC会截断而非四舍五入小数位。开发者在涉及金额、数量等关键业务计算时,应明确数值语义并设计容错机制。
【Linux】多线程7——线程池
池化技术指的是提前准备一些资源,在需要时可以重复使用这些预先准备的资源。在系统开发过程中,我们经常会用到池化技术。通俗的讲,池化技术就是:把一些资源预先分配好,组织到对象池中,之后的业务使用资源从对象池中获取,使用完后放回到对象池中。这样做带来几个明显的好处:池化技术简单点来说,就是提前保存大量的资源,以备不时之需。池化技术有两个特点,提前创建和重复利用。 由于在实际应用当做,分配内存、创建进程、线程都会设计到一些系统调用,系统调用需要导致程序从用户态切换到内核态,是非常耗时的操作。因此,当程
YOLOv8改进策略【损失函数篇】| 替换Powerful-IoU(PIoU),增强对中等质量锚框的关注力,引导锚框更直接、高效地回归
现有基于IoU的损失函数存在不合理的惩罚因子,导致锚框在回归过程中出现面积扩大的问题,使得回归效率降低、收敛速度变慢。同时,这些损失函数在反映锚框与目标框之间的差异、考虑目标框大小以及某些情况下的性能表现等方面存在局限性。在目标检测任务中,边界框回归的损失函数对检测性能至关重要。Powerful-IoU(PIoU)及其升级版PIoU v2正是为解决现有损失函数存在的问题而设计的。本文利用PIoU改进YOLOv8的损失函数,提高模型精度。
【多线程】互斥锁 {竞态条件与同步机制;多线程的数据竞争问题,互斥锁的基本用法,pthread_mutex系列函数,互斥锁的原理;可重入函数和线程安全;死锁;其他常见的各种锁}
【多线程】互斥锁 {竞态条件与同步机制;多线程的数据竞争问题,互斥锁的基本用法,pthread_mutex系列函数,互斥锁的原理;可重入函数和线程安全;死锁;其他常见的各种锁}
基于 Langchain 开发一个完整的支持多轮数据分析(直连 mysql 数据,多表综合分析 SQL 取数,数据分析,报表生成)ChatBI 系统(前后端完整实现源代码)
ChatBI系统开发摘要 本文介绍了基于Langchain的多轮数据分析ChatBI系统开发方案。该系统支持MySQL数据库连接,提供多表分析、SQL查询、数据分析和报表生成功能。系统采用前后端分离架构:前端使用React+Ant Design+ECharts实现交互界面;后端基于FastAPI搭建服务,集成Langchain处理自然语言到SQL的转换;核心技术栈还包括SQLAlchemy、Pandas和Matplotlib。 系统核心模块包括: 数据库连接层:使用SQLAlchemy管理MySQL连接 L
MediaPipe 从入门到精通:安装、配置与多场景应用实战手册
人体姿态检测是 MediaPipe 的核心功能之一,它能够从图像或视频中识别人体姿态,并输出关键点的坐标。这些关键点覆盖了身体的主要部位,例如肩膀、肘部、髋部、膝盖等,总计 33 个点。每个关键点包含 x、y、z 坐标(归一化到 0-1 范围)以及可见性评分,可用于分析动作、姿势或开发健身、游戏等应用。手部关键点检测是 MediaPipe 的另一大亮点,它可以识别图像或视频中的手部,并输出 21 个关键点的坐标。这些关键点覆盖手掌和手指的各个部位,适用于手势识别、虚拟现实或交互式应用。
【linux线程(四)】初识线程池&手撕线程池
本篇文章着重讲解了线程池的概率以及如何手撕线程池,还拓展讲解了读写锁和池化技术的知识,最后,为面试手撕线程池做了一个简易版的demo
SAP_PP模块定额工艺路线简介
在 SAP PP(生产计划)模块中,定额工艺路线(Routing) 是生产制造流程中的核心主数据之一,用于定义制造一个产品所需的标准操作步骤。工艺路线详细描述了生产过程中的各个工序、使用的工作中心、标准作业时间、资源分配等信息,是进行生产计划、成本核算、排产控制、车间执行等功能的基础。
Linux之线程池
线程池是提升Linux程序性能的利器,它通过复用固定数量的线程来处理异步任务。但其核心的“生产者-消费者”模型(任务队列 + 工作线程)也潜藏着死锁风险。 主要风险源于任务间的隐式依赖。当一个任务(Task A)的执行结果依赖于另一个任务(Task B)时,如果所有线程都在等待类似Task A的依赖任务完成,而Task B因线程耗尽而无法被调度执行,整个线程池就会陷入相互等待的僵局,即池-induced死锁。
TMS_WebGMaps_1.9.8.0_Full_Source
TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder
IDEA的使用指南
IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.
Linux 线程池
线程池的实现与常见问题解答
C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片
基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正
【Linux】线程池
线程池是一种线程使用模式,线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
Devexpress16.2.6破解工具
Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具
【Linux】线程池模拟
线程池是线程的一种管理模式,它会预先创建好线程放在容器中待命,当有任务时会分配线程完成任务,而不是当有任务时再创建新的线程。执行完任务后会重新回到线程池中进行等待。一个简单的线程池需要包含任务队列,线程管理,任务处理,日志打印等。
[Linux]线程池
本文详细介绍如何使用加锁的懒汉式单例实现线程池
Linux_实现线程池
在Linux下实现一个线程池,线程池就是创建多个线程,然后对这些线程进行管理,并且可以发放任务给到线程池,让线程池完成任务。
Linux —— 线程池
线程池(Thread Pool)是线程的一种使用方式。它通过预先创建一组线程并管理它们的生命周期,来提高多线程应用程序的性能和资源利用率。线程池的核心思想是减少在创建和销毁线程时所产生的开销。
579



被折叠的 条评论
为什么被折叠?



