范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

linux线程池的作用应用场景工作原理与纯C实现

  前言
  本文介绍线程池的作用、线程池的应用场景、线程池的工作原理、代码实现线程池以及与nginx的线程池对比分析。 线程池的作用
  为什么会有线程池,到底解决了什么问题 减少线程的创建与销毁(线程的角度) 异步解耦的作用(设计的角度) 线程池的异步处理使用场景
  以日志为例,在写日志loginfo("xxx"),与日志落盘,是两码事,它们两之间应该是异步的。那么异步解耦就是将日志当作一个任务task,将这个任务抛给线程池去处理,由线程池去负责日志落盘。对于应用程序而言,就可以提升落盘的效率。
  以nginx为例,一秒几万的请求,速度很快。如果在其中加一个日志,那么qps一下子就掉下来了,因为每请求一次就需要落盘一次,那么整个服务器的性能就下降。我们可以引入一个线程池,把日志这个任务抛给线程池,对于主循环来说,就只抛任务即可,这样就可以大大提升主线程的效率。这就是线程池异步解耦的作用
  不仅仅是日志落盘,还有很多地方都可以用线程池,比较耗时的操作如数据库操作,io处理等,都可以用线程池。
  线程池有必要将线程与cpu做亲和性吗? 在注重cpu处理能力的时候,可以做黏合;如果注重的是异步解耦,那么这里更加注重的是任务,没必要将线程和cpu做绑定。 线程池工作原理线程池应该提供哪些api
  我们在使用线程池的时候,是当作一个组件去使用。所以在使用组件的时候,我们首先想到的是线程池应该提供哪些api。 线程池的初始化(创建) init/create 往池里面抛任务push_task 线程池的销毁 deinit/destroy
  这三个api是最核心的api,其他可扩展的api都是可有可无的,而这三个api是一定要有的。 线程池的三个组件
  想象去银行营业厅的场景。柜员:为客户提供服务;客户:是来办业务的,对于柜员来说,这些人就是任务。那么这两个形象就构建出了pthread和task。
  那么这个公示牌(xxx号来几号柜台办理业务),是谁的属性呢?告示牌的作用是管理客户和柜员有秩序工作,它不隶属于柜员,也不隶属于客户,它是一个管理工具。 柜员 ---->pthread 客户 ---->task 告示牌–>管理柜员和客户有秩序的工作(不会出现一个任务同时被多个线程处理的情况)
  这么这就自然而然的形成了3个组件,那么它们都应该有什么属性呢: 对于柜员来说:工号id,停止工作标识符flag 对于客户来说:如果办理取款需要带银行卡,如果办贷款需要带凭证等等,所以需要一个任务func(),以及对应任务的参数arg 对于告示牌来说:如果没有客户,那么柜员就需要在工作中等待客户的到来,所以第一个需要条件等待cond,既然要管理有秩序的工作,肯定需要mutex来保证临界资源
  下面将柜员称为执行队列,客户称为任务队列,告示牌称为池管理组件。
  错误理解:要使用线程就从线程池里面拿一个线程出来使用,用完再返回给线程池。这种理解是连接池的概念。而线程池是多个线程去任务队列取任务,竞争任务。
  所以线程的核心就是下面的伪代码: while(1){    get_task();    task->func();}
  相关视频推荐
  150行代码,带你手写线程池,自行准备linux环境
  cpu密集型和io密集型的线程池在开源框架中的应用
  学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
  需要C/C++ Linux服务器架构师学习资料加qun 812855908 获取(资料包括 C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg 等),免费分享
  代码实现线程池的任务队列、执行队列、池管理组件 的定义 与 添加删除
  //执行队列typedef struct NWORKER {    pthread_t id;    int termination;    struct NTHREADPOLL *thread_poll;    struct NWORKER *prev;    struct NWORKER *next;} worker_t;//任务队列typedef struct NTASK {    void (*task_func)(void *arg);    void *user_data;    struct NTASK *prev;    struct NTASK *next;} task_t;//池管理组件typedef struct NTHREADPOLL {    worker_t *workers;    task_t *tasks;    pthread_cond_t cond;    pthread_mutex_t mutex;} thread_poll_t;
  //头插法#define LL_ADD(item, list)do{       item->prev=NULL;                item->next=list;                if(list!=NULL){                     list->prev=item;            }                               list=item                   }while(0)#define LL_REMOVE(item, list)do{            if(item->prev!=NULL){                       item->prev->next=item->next;        }                                       if(item->next!=NULL){                       item->next->prev=item->prev;        }                                       if(list==item){                             list=item->next;                    }                                       item->prev=item->next=NULL;         }while(0)三个api
  创建其实就是创建thread_poll_t结构体,然后按照给定的宏创建线程和worker。
  push就是给task队列增加一个任务,然后用signal通知cond。
  销毁将所有线程的termination置1,然后广播cond即可。 //return access create thread num;int thread_poll_create(thread_poll_t *thread_poll, int thread_num) {    if (thread_num < 1)thread_num = 1;    memset(thread_poll, 0, sizeof(thread_poll_t));    //init cond    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;    memcpy(&thread_poll->cond, &blank_cond, sizeof(pthread_cond_t));    //init mutex    pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;    memcpy(&thread_poll->mutex, &blank_mutex, sizeof(pthread_mutex_t));    // one thread one worker    int idx = 0;    for (idx = 0; idx < thread_num; idx++) {        worker_t *worker = malloc(sizeof(worker_t));        if (worker == NULL) {            perror("worker malloc err ");            return idx;        }        memset(worker, 0, sizeof(worker_t));        worker->thread_poll = thread_poll;        int ret = pthread_create(&worker->id, NULL, thread_callback, worker);        if (ret) {            perror("pthread_create err ");            free(worker);            return idx;        }        LL_ADD(worker, thread_poll->workers);    }    return idx;}int thread_poll_push_task(thread_poll_t *thread_poll, task_t *task) {    pthread_mutex_lock(&thread_poll->mutex);    LL_ADD(task, thread_poll->tasks);    pthread_cond_signal(&thread_poll->cond);    pthread_mutex_unlock(&thread_poll->mutex);}int thread_destroy(thread_poll_t *thread_poll) {    worker_t *worker = NULL;    for (worker = thread_poll->workers; worker != NULL; worker = worker->next) {        worker->termination = 1;    }    pthread_mutex_lock(&thread_poll->mutex);    pthread_cond_broadcast(&thread_poll->cond);    pthread_mutex_unlock(&thread_poll->mutex);}线程的回调函数
  线程要做的就是取任务,执行任务。取任务从任务队列里面取。 task_t *get_task(worker_t *worker) {    while (1) {        pthread_mutex_lock(&worker->thread_poll->mutex);        while (worker->thread_poll->workers == NULL) {            if (worker->termination)break;            pthread_cond_wait(&worker->thread_poll->cond, &worker->thread_poll->mutex);        }        if (worker->termination) {            pthread_mutex_unlock(&worker->thread_poll->mutex);            return NULL;        }        task_t *task = worker->thread_poll->tasks;        if (task) {            LL_REMOVE(task, worker->thread_poll->tasks);        }        pthread_mutex_unlock(&worker->thread_poll->mutex);        if (task != NULL) {            return task;        }    }};void *thread_callback(void *arg) {    worker_t *worker = (worker_t *) arg;    while (1) {        task_t *task = get_task(worker);        if (task == NULL) {            free(worker);            pthread_exit("thread termination ");        }        task->task_func(task);    }}测试代码
  这里我们创建了1000个task,开了10个thread。记住task以及task的参数,由task的func来销毁。 //// Created by 68725 on 2022/7/25.//#include #include #include #include #include //头插法#define LL_ADD(item, list)do{       item->prev=NULL;                item->next=list;                if(list!=NULL){                     list->prev=item;            }                               list=item;                  }while(0)#define LL_REMOVE(item, list)do{            if(item->prev!=NULL){                       item->prev->next=item->next;        }                                       if(item->next!=NULL){                       item->next->prev=item->prev;        }                                       if(list==item){                             list=item->next;                    }                                       item->prev=item->next=NULL;         }while(0)//执行队列typedef struct NWORKER {    pthread_t id;    int termination;    struct NTHREADPOLL *thread_poll;    struct NWORKER *prev;    struct NWORKER *next;} worker_t;//任务队列typedef struct NTASK {    void (*task_func)(void *arg);    void *user_data;    struct NTASK *prev;    struct NTASK *next;} task_t;//池管理组件typedef struct NTHREADPOLL {    worker_t *workers;    task_t *tasks;    pthread_cond_t cond;    pthread_mutex_t mutex;} thread_poll_t;task_t *get_task(worker_t *worker) {    while (1) {        pthread_mutex_lock(&worker->thread_poll->mutex);        while (worker->thread_poll->workers == NULL) {            if (worker->termination)break;            pthread_cond_wait(&worker->thread_poll->cond, &worker->thread_poll->mutex);        }        if (worker->termination) {            pthread_mutex_unlock(&worker->thread_poll->mutex);            return NULL;        }        task_t *task = worker->thread_poll->tasks;        if (task) {            LL_REMOVE(task, worker->thread_poll->tasks);        }        pthread_mutex_unlock(&worker->thread_poll->mutex);        if (task != NULL) {            return task;        }    }};void *thread_callback(void *arg) {    worker_t *worker = (worker_t *) arg;    while (1) {        task_t *task = get_task(worker);        if (task == NULL) {            free(worker);            pthread_exit("thread termination ");        }        task->task_func(task);    }}//return access create thread num;int thread_poll_create(thread_poll_t *thread_poll, int thread_num) {    if (thread_num < 1)thread_num = 1;    memset(thread_poll, 0, sizeof(thread_poll_t));    //init cond    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;    memcpy(&thread_poll->cond, &blank_cond, sizeof(pthread_cond_t));    //init mutex    pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;    memcpy(&thread_poll->mutex, &blank_mutex, sizeof(pthread_mutex_t));    // one thread one worker    int idx = 0;    for (idx = 0; idx < thread_num; idx++) {        worker_t *worker = malloc(sizeof(worker_t));        if (worker == NULL) {            perror("worker malloc err ");            return idx;        }        memset(worker, 0, sizeof(worker_t));        worker->thread_poll = thread_poll;        int ret = pthread_create(&worker->id, NULL, thread_callback, worker);        if (ret) {            perror("pthread_create err ");            free(worker);            return idx;        }        LL_ADD(worker, thread_poll->workers);    }    return idx;}int thread_poll_push_task(thread_poll_t *thread_poll, task_t *task) {    pthread_mutex_lock(&thread_poll->mutex);    LL_ADD(task, thread_poll->tasks);    pthread_cond_signal(&thread_poll->cond);    pthread_mutex_unlock(&thread_poll->mutex);}int thread_destroy(thread_poll_t *thread_poll) {    worker_t *worker = NULL;    for (worker = thread_poll->workers; worker != NULL; worker = worker->next) {        worker->termination = 1;    }    pthread_mutex_lock(&thread_poll->mutex);    pthread_cond_broadcast(&thread_poll->cond);    pthread_mutex_unlock(&thread_poll->mutex);}void counter(task_t *task) {    int idx = *(int *) task->user_data;    printf("idx:%d  pthread_id:%llu ", idx, pthread_self());    free(task->user_data);    free(task);}#define THREAD_COUNT 10#define TASK_COUNT 1000int main() {    thread_poll_t thread_poll = {0};    int ret = thread_poll_create(&thread_poll, THREAD_COUNT);    if (ret != THREAD_COUNT) {        thread_destroy(&thread_poll);    }    int i = 0;    for (i = 0; i < TASK_COUNT; i++) {        //create task        task_t *task = (task_t *) malloc(sizeof(task_t));        if (task == NULL) {            perror("task malloc err ");            exit(1);        }        task->task_func = counter;        task->user_data = malloc(sizeof(int));        *(int *) task->user_data = i;        //push task        thread_poll_push_task(&thread_poll, task);    }    getchar();    thread_destroy(&thread_poll);}nginx线程池实现对比分祈线程池初始化对比
  cond初始化,mutex初始化,创建线程
  线程回调函数对比
  取任务,执行任务
  push任务对比
  nginx是将任务插到尾部,我们做的是插到头部
  线程数量的抉择
  线程到底初始化多少呢?如果是计算密集型就不用太多的线程,如果是任务密集型可以多几个。以下是经验值,不一定一定按照这个来。 计算密集型:强计算,计算时间较长,线程数量与cpu核心数成比例即可,如1:1。 任务密集型:处理任务,io操作。可以开多一点,如cpu核心数的2倍。 线程池的动态扩缩
  随着任务越来越多,线程不够用怎么办?我们可以开一个监控线程,设n=running线程 / 总线程。当n>上水位时,监控线程创建几个线程;当n<下水位时,监控线程销毁几个线程。可以设置30%和70%。

新加坡去年物价疯涨,今年会好吗?涨涨涨!过去一年,涨价成了新加坡人嘴边最常说的词之一。本周三,新加坡贸工部和金融管理局发布了最新通货膨胀数据。新加坡去年12月核心消费者价格指数(CPI),与前年同期相比,上涨5。医药行业即将起飞,赠送大家一份医药藏宝图,请收好!3年YQ,由新冠带来的不确定性如今已经可以确定,在此期间,许多大大小小的医药公司股价表现不尽如人意,自2021年7月至今,指数最大跌幅超过30,从最热门赛道到无人问津这里就拿医药四重要提示云门山风景区关于免景区门票的公告云门山风景区关于免景区门票的公告按照上级部门关于全省国有A级旅游景区免首道门票的部署,自1月21日至3月31日青州云门山风景区将免门票开放,欢迎广大游客前来游玩。一免票时间2023明日起至3月31日,崂山风景区面向国内外游客免门票!半岛全媒体记者刘红2023年1月21日至2023年3月31日,崂山风景区面向国内外游客免门票。公告如下根据青岛市文化和旅游局青岛市财政局印发青岛市关于大力提振文化和旅游消费的政策措最惨星二代猝死败光亿万家产4次离婚,从小富养却一生悲剧范主说金钱诅咒?上周,一代摇滚巨星猫王的独生女LisaMariePresley,因心脏骤停抢救无效,在美国加州猝然离世,终年仅54岁。她77岁的母亲知名女演员PriscillaPr如何使用QtCreator为项目添加新的文件一导读当使用QtCreator的新工程创建向导创建好一个最基本的项目工程后,我们则需要往项目工程中添加新的文件用于描述项目。一般情况下,在项目设计阶段,则会规划出具体的描述文件有哪80后游资打造妖股4个涨停板,被罚429万,证监会文件揭秘操盘细节1概述小江,80后小哥哥,人在杭州西湖区,从2020年8月19日到8月24日,使用4个证券账户,操作妖股天山生物,4个交易日从5。67飙升到9。31价位(该股大行情的12个交易日从最全面的失业金领取政策,你一定要知道!和灵活就业人员无关哦!关注我,社保就业和各类补贴政策绝对不迷路!我这个曾经的专业人士明确告诉大家,灵活就业人员买不买社保都不能领取失业金。因为灵活就业人员购买的社保只有养老保险,没有失业保险,何来失业金为什么二孩政策放开,生育率反而连年走低?中国现在已经进入人口老龄化阶段,无论是经济还是生活,都受老龄化问题的影响。放开三胎全面放开二孩后生育率反降老龄化问题严重等有关生育和老龄化的热烈讨论接连不断。这些话题成为了生育话题庐山免门票!最新公告庐山旅游发展委员会发布关于面向境内外游客免门票的公告速看详情兔年大吉关于庐山风景区面向境内外游客免门票的公告为进一步回馈广大游客,扩大文旅消费,做实唱响庐山天下悠品牌,经研究决定,软件测试系列Pytest用例执行顺序只有一个py文件如果测试case只存在于单个。py文件,测试case默认从上到下执行。可以使用pytestordering来控用例执行顺序。pytest。mark。run(orde
科学家发现罕见恒星,可能由白矮星合并产生?恒星作为宇宙中最为重要的天体,也是宇宙光和热的主要来源。宇宙中的恒星,都依靠核聚变产生光和热,一颗年轻的恒星,必然会富含氢元素和氦元素,通过氢氦核聚变向外界传播光和热,恒星表面也会科学家第六次物种大灭绝正在发生!七种灭绝事件或终结地球生命地球在经历第六次生命大灭绝!2022年1月10日,美国夏威夷大学的一位生物学家在BiologicalReviews上的研究论文中声称地球正在经历第六次物种大灭绝,并列举大量的证据。天文学家认为他们已探测到一个隐形的黑洞天文学家在2019年拍到了有史以来第一张黑洞的直接图像,这要归功于在黑洞中发光的物质。但许多黑洞实际上几乎不可能被探测到。现在,另一个使用哈勃太空望远镜的团队似乎终于发现了以前没有嫦娥五号月壤样品研究取得新成果我科学家建立新的月球年代函数模型原标题嫦娥五号月壤样品研究取得新成果我科学家建立新的月球年代函数模型记者齐芳从中国科学院空天信息创新研究院(以下简称空天院)获悉,该院遥感科学国家重点实验室行星遥感团队及合作者,利春天,多给孩子喝8种营养汤羹,钙含量高,营养丰富春天是万物生长的季节,也是孩子长个的黄金期,很多家长只知道给孩子喝牛奶来补钙,其实光喝牛奶钙含量是有限的,下面推荐8种汤羹,钙含量高,每天换着花样给孩子喝。一排骨海带汤所需食材干海锂电双雄,谁将主宰2022年电池市场?能源人都在看,点击右上角加关注动力电池双雄三元电池和磷酸铁锂电池在未来一年,产量和装机量情况将会如何?三元不会被铁锂取代,成本劣势在减弱2021年,整个三元锂电池的市场的确受到了磷冰箱线上市场一超两强稳定日韩品牌溃败新飞跻身前五钉科技观察在疫情持续原材料涨价深处存量市场等多重不利因素制约下,冰箱市场近年来下行压力渐增。钉科技注意到,相比低迷的线下市场,冰箱线上市场在2021年度依然保持着较高的增速。根据奥刚刚公布!明天起,河南226家免费来源河南广电映象网为贯彻落实河南省人民政府办公厅关于进一步做好惠企纾困工作促进经济平稳健康发展的通知文件精神,全面推动文化旅游企业节后生产经营,着力促进经济平稳运行,2月15日,河澳洲官宣返澳新规!小心被罚!37个中国人遭遣返附入境申请步骤最近要返澳的小伙伴注意了,入境时,数字旅客声明即将取代澳大利亚旅行声明(ATD)!这一规定细则,也在最近正式宣布啦!如果在2月18日之前入境澳洲,那么可以继续填写ATD表格。如果是流鼻涕流鼻血打喷嚏怎么办这些知识孩子应该早点知道快来和大耳朵图图一起探索鼻子的奥秘吧!鼻子为什么能闻到味道?鼻腔里的鼻黏膜嗅区上分布着大量的嗅细胞。当嗅细胞上的纤毛捕捉到气味时,会马上通过神经向大脑报告,这时,鼻子就能辨别各种气真心希望拥有这样一个朋友在芸芸众生滚滚红尘之中,真心希望拥有这样的一个朋友与性别无关,与年龄无关,与贫富无关,与地位无关,与学历无关,与美丑无关同频同道,同心同德,心心相印,襟怀坦荡。在一起时能毫无顾忌无