Linux线程池

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.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;
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)
{
    /*构造一个新任务*/
     CThread_worker *newworker =(CThread_worker *) malloc (sizeof (CThread_worker));
     newworker->process = process;
     newworker->arg = arg;
     newworker->next = 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_destroy ()
{
    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++)
         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);
    /*销毁后指针置空是个好习惯*/
     pool=NULL;
    return 0;
}
void * thread_routine (void *arg)
{
     printf ("starting thread 0x%x\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%x 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%x 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));


        /*调用回调函数,执行任务*/
         (*(worker->process)) (worker->arg);
         free (worker);
         worker = NULL;
     }
    /*这一句应该是不可达的*/
     pthread_exit (NULL);
}

 //   下面是测试代码

void *myprocess (void *arg)
{
     printf ("threadid is 0x%x, 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++)
     {
         workingnum[i] = i;
         pool_add_worker (myprocess, &workingnum[i]);
     }
    /*等待所有任务完成*/
     sleep (5);
    /*销毁线程池*/
		pool_destroy ();
		free (workingnum);
		return 0;
}
 
STM32F407用FSMC+DMA驱动LVGL,3.5寸屏流畅度翻倍实战(附CubeMX配置避坑) 本文详细介绍了如何在STM32F407上通过FSMC+DMA驱动LVGL,显著提升3.5寸屏的显示流畅度。从FSMC与DMA的配置原理到LVGL驱动层适配,提供了完整的优化方案和实测数据,帮助开发者解决界面卡顿问题,实现流畅度翻倍的效果。 阅读详情

相关推荐

亚马逊SP-API授权实战:从OAuth流程到Refresh Token获取

本文详细解析了亚马逊SP-API授权流程,从OAuth认证到Refresh Token获取的全过程。通过实战经验分享,帮助开发者快速掌握Marketplace Appstore、Website Workflow和自行授权三种方式,解决常见错误如MD5100和MD9999,并提供了安全存储Refresh Token的最佳实践。

weixin_30379531的博客 518

四种最常见的线程池代码示例

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * 线程池 * newCachedTheadPool 可缓存线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,若无可回收,则新建线程 .

窗外的羊 2123

2022-04-06 RK3566 上调试百兆以太网卡YT8512C 调试记录

一、原理图 二、dts &gmac1_clkin{ clock-frequency = <50000000>; status = "okay"; }; &gmac1 { phy-mode = "rmii"; clock_in_out = "input"; snps,reset-gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>; snps,reset-active-low; sn...

海月汐辰 1万+

线程池(ThreadPoolExecutor)源码解析

目录一、线程池概念介绍1.1、什么是线程池1.2、线程池工作流程1.3、线程池的代码用例二、源码解析——构造函数2.1、线程池的构造函数及类的继承关系2.2、Executors提供的线程池模板2.3、拒绝策略的实现2.4、任务队列BlockingQueue的实现三、 源码解析——execute(Runnable command)3.1、流程概述 一、线程池概念介绍 1.1、什么是线程池 池化技术其实在技术生态圈中是比较常见的,比如:对象池、连接池等等。 为什么会有线程池这个东西存在呢?其实原因跟其他池化技

小志的博客 8748

从AT指令到万物互联:移远EG800K-CN模块的协议栈深度解析与实践指南

本文深度解析移远EG800K-CN 4G模块的协议栈架构与AT指令体系,涵盖MQTT云端集成、多协议配置优化及工业级故障排除指南。通过实战示例展示如何利用该模块构建稳定可靠的物联网连接方案,实现从设备到云端的万物互联。

jupyter5notebook的博客 362

手把手教你绕过网易易盾验证码:滑块、点选、语序全攻略

本文深度解析了以网易易盾为代表的现代验证码技术,重点探讨了滑块、点选、语序及空间推理等交互式验证码的工作原理与对抗策略。文章从行为验证和空间推理的核心逻辑出发,剖析了验证码交互的数据流与关键参数,并提供了模拟人类行为轨迹、维护设备指纹等工程实践方法,旨在帮助开发者在合规前提下设计更健壮的自动化流程。

3c4x5z6v7b的博客 699

线程池及其代码

用来管理和维护多个线程,避免在短时间内创建和销毁线程的代价,不仅能够,而且能够。

m0_64028711的博客 591

解决Keil uVision许可证管理中Unknown Product错误

嵌入式开发中,IDE工具的许可证管理是确保开发环境正常运行的关键环节。Keil uVision作为ARM架构的主流开发工具,其许可证系统采用加密验证机制,通过产品版本识别实现授权控制。当出现Unknown Product错误时,通常源于版本兼容性问题或区域发行版差异,这直接影响开发工具链的可用性。特别是在维护历史项目或使用中国特供版时,开发者常会遇到此类问题。通过分析许可证类型、调整安装配置或建立虚拟化开发环境等工程实践方案,可以有效解决这类授权验证故障,保障嵌入式项目的持续集成与交付效率。

weixin_33743248的博客 363

线程池详解及完整代码实现

线程池完整代码实现

weixin_46935110的博客 1310

【局部规划模块曲线算法】曲线平滑介绍

本文先对轨迹平滑问题做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容(1)适合给移动机器人运动的路径【满足运动学,高阶平滑】(2)高阶的运动学不能够突变的【至少三阶的加速度不能突变,最好四阶的jerk和五阶的snap也不能突变】(3)在转弯的地方不会停下来(4)加减速均衡,节省能量(5)节省时间的。

qq_35635374的博客 5715

在 SAP BTP 中通过 MTA 自动创建 Service Broker 的原理与实战

本文探讨了如何在SAP BTP的Cloud Foundry环境中通过MTA部署自动创建和注册Service Broker。传统手动注册方式存在依赖管理员、环境一致性差等问题。通过MTA部署可实现自动化Broker注册,利用占位符生成安全凭证,并确保平台端与应用端认证一致。文章详细解析了关键配置参数,包括create-service-broker标志、Broker名称、认证凭据和访问URL的设置方法。这种基础设施即代码(IaC)方式能提升DevOps实践水平,使服务注册成为应用部署流水线的有机组成部分。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 200

【Linux】线程池

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

m0_61438674的博客 1324

Go语言爬虫:chromedp 的详细使用

chromedp 是 Go 语言中无头浏览器自动化的终极利器。它能驱动真实的 Chrome 浏览器,处理 JavaScript 渲染、复杂交互和反爬虫机制

数据知道的博客 4492

【linux线程(四)】初识线程池&手撕线程池

本篇文章着重讲解了线程池的概率以及如何手撕线程池,还拓展讲解了读写锁和池化技术的知识,最后,为面试手撕线程池做了一个简易版的demo

杭电码农-NEO的博客 1855

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Linux 线程池

线程池的实现与常见问题解答

天行健、君子以自强不息 1255

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【Linux】线程池模拟

线程池是线程的一种管理模式,它会预先创建好线程放在容器中待命,当有任务时会分配线程完成任务,而不是当有任务时再创建新的线程。执行完任务后会重新回到线程池中进行等待。一个简单的线程池需要包含任务队列,线程管理,任务处理,日志打印等。

2401_86449430的博客 1万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Linux之线程池

线程池是提升Linux程序性能的利器,它通过复用固定数量的线程来处理异步任务。但其核心的“生产者-消费者”模型(任务队列 + 工作线程)也潜藏着死锁风险。 主要风险源于任务间的隐式依赖。当一个任务(Task A)的执行结果依赖于另一个任务(Task B)时,如果所有线程都在等待类似Task A的依赖任务完成,而Task B因线程耗尽而无法被调度执行,整个线程池就会陷入相互等待的僵局,即池-induced死锁。

2402_84532723的博客 3612

[Linux]线程池

本文详细介绍如何使用加锁的懒汉式单例实现线程池

我的博客 1077

Linux_实现线程池

在Linux下实现一个线程池,线程池就是创建多个线程,然后对这些线程进行管理,并且可以发放任务给到线程池,让线程池完成任务。

安权_code的博客 1212

Linux —— 线程池

线程池(Thread Pool)是线程的一种使用方式。它通过预先创建一组线程并管理它们的生命周期,来提高多线程应用程序的性能和资源利用率。线程池的核心思想是减少在创建和销毁线程时所产生的开销。

知其然 知其所以然 1273
上一篇: informix 锁
下一篇: 文件I/O 互斥操作 select
「已注销」
博客等级 码龄19年 22粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值