使用c++11写个最简跨平台线程池(转载)

【zz】webrtc线程模型 #- 转载 作者 webrtc的base的 thread,是我见过的封装最帅的c++线程库,根据比qt的还好用,发个例子给你 using namespace webrtc; using namespace rtc; //std::cout<<"Thread::Current():" << Thread::Current()->GetId(); //Thread::C... 阅读详情

为什么需要多线程?

最简单的多线程长啥样?

为什么需要线程池,有什么问题?

实现的主要原理是什么?

 

带着这几个问题,我们依次展开。

1.为什么需要多线程?

    大部分程序毕竟都不是计算密集型的,简单的说,正常情况下,以单线程的模式来写对程序员而言是最舒心的。因为所有的代码都是顺序执行,非常容易理解!函数一级一级往下调用,代码一行一行执行。但是,代码的世界里,虽然cpu还好,但是却经常需要用到io资源,或者是其他服务器的网络资源,比如像数据库,如果这个时候因此把进程卡住,不管是客户端还是客户端都对用户体验相当糟糕。当然了,计算密集型的运算就更需要多线程,防止主线程被卡住。

2.最简单的多线程长啥样?

    举个最简单的例子,服务器采用阻塞式socket,有一个网络线程负责收发包(IO),然后有一个逻辑主线程负责相应的业务操作,主线程和网络线程之间通过最简单的消息队列进行交换,而这个消息队例明显是两个线程都要访问(轮询消息队列是否为空)到的,所以,我们需要给这个消息队列上锁(std::mutex),即可以解决问题。由于比较简单我们就不需要看这个怎么码了。这种模式虽然简单,但是在合适的岗位上,也是极好的!

3.那为什么需要线程池呢,有什么问题?

   还以刚才的服务器举例,如果业务线程逻辑比较复杂,又或者他需要访问数据库或者是其他服务器的资源,读取文件等等呢?当然他可以采用异步的数据库接口,但是采用异步意味着业务代码被碎片化。异步是典型的讨厌他,但是又干不掉他的样子。离题了。回归。这个时候我们需要多个业务线程处理了。多个线程就意味着多一份处理能力!回到上个问题,我们的多线程采用轮询消息队列的方式来交换信息,那么这么多个线程,不断的上锁解锁,光这个成本就够了。这个时候,条件变量就上线了(std::condition_variable)就登场了

4.实现的主要原理是什么?

    业务线程不要轮询消息队列了,而所有的业务线程处于等待状态,当有消息再来的时候,再由产生消息的人,在我们示例场景就是网络线程了,随便唤醒一个工人线程即可。看看最关键的代码

 //消费者
void consumer()
{
    //第一次上锁
    std::unique_lock < std::mutex > lck(mutex_);
    while (active_)
    {
        //如果是活动的,并且任务为空则一直等待
        while (active_ && task_.empty())
            cv_.wait(lck);
 
        //如果已经停止则退出
        if(!active_)
            break;
 
        T *quest = task_.front();
        task_.pop();
 
        //从任务队列取出后该解锁(任务队列锁)了
        lck.unlock();
 
        //执行任务后释放
        proc_(quest);
 
        //delete quest;   //在proc_已经释放该指针了
 
        //重新上锁
        lck.lock();
    }
}
//算了,还是直接贴完整代码,看注释吧
#ifndef _WORKER_POOL_H_
#define _WORKER_POOL_H_
 
//file: worker_pool.h
 
//#define  _CRT_SECURE_NO_WARNINGS
// g++ -g -std=c++11 1.cc -D_GLIBCXX_USE_NANOSLEEP -lpthread */
 
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
//#include <chrono>
 
template<typename T>
class WorkerPool
{
public:
    typedef WorkerPool<T> THIS_TYPE;
    typedef std::function<void(T*)> WorkerProc;
    typedef std::vector< std::thread* > ThreadVec;
 
    WorkerPool()
    {      
        active_ = false;
    }
    virtual ~WorkerPool()
    {
        for(ThreadVec::iterator it = all_thread_.begin();it != all_thread_.end();++it)
            delete *it;
        all_thread_.clear();
    }
    void Start(WorkerProc f,int worker_num=1)
    {
        active_ = true;    
        all_thread_.resize(worker_num);
        for (int i = 0; i < worker_num;i++ )
        {
            all_thread_[i] = new std::thread(std::bind(&THIS_TYPE::consumer,this));
        }
        proc_ = f;
    }
    //生产者
    void Push(T *t)
    {
        std::unique_lock < std::mutex > lck(mutex_);
        task_.push(t);
        cv_.notify_one();
    }
 
    void Stop()
    {
        //等待所有的任务执行完毕
        mutex_.lock();
        while (!task_.empty())
        {  
            mutex_.unlock();
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            cv_.notify_one();
            mutex_.lock();
        }
        mutex_.unlock();
 
        //关闭连接后,等待线程自动退出
        active_ = false;
        cv_.notify_all();
        for(ThreadVec::iterator it = all_thread_.begin();
            it != all_thread_.end();++it)
            (*it)->join();
    }
private:
    //消费者
    void consumer()
    {
        //第一次上锁
        std::unique_lock < std::mutex > lck(mutex_);
        while (active_)
        {
            //如果是活动的,并且任务为空则一直等待
            while (active_ && task_.empty())
                cv_.wait(lck);
 
            //如果已经停止则退出
            if(!active_)
                break;
 
            T *quest = task_.front();
            task_.pop();
 
            //从任务队列取出后该解锁(任务队列锁)了
            lck.unlock();
 
            //执行任务后释放
            proc_(quest);
 
            //delete quest;   //在proc_已经释放该指针了
 
            //重新上锁
            lck.lock();
        }
    }
 
    std::mutex mutex_;
    std::queue<T*> task_;
    std::condition_variable cv_;
    bool active_;
    std::vector< std::thread* > all_thread_;
    WorkerProc proc_;
};
 
#endif
//写一个类继承一下,并写一个工作函数和回调函数处理
#include "worker_pool.h"
#include <iostream>
 
//为了多耗点cpu,计算斐波那契数列吧
static int fibonacci(int a)
{
    //ASSERT(a > 0);
    if (a == 1 || a == 2)
        return 1;
    return fibonacci(a-1) + fibonacci(a-2);
}
 
//异步计算任务
struct AsyncCalcQuest
{
    AsyncCalcQuest():num(0),result(0)
    {}
    //计算需要用到的变量
    int num;
    int result;
};
 
//为了测试方便,引入全局变量用于标识线程池已将所有计算完成
const int TOTAL_COUNT = 1000000;
int now_count = 0;
 
//继承一下线程池类,在子类处理计算完成的业务,在我们这里,只是打印一下计算结果
class CalcWorkerPool:public WorkerPool<AsyncCalcQuest>
{
public:
    CalcWorkerPool(){}
 
    virtual ~CalcWorkerPool()
    {
    }
 
    //在工人线程中执行
    void DoWork(AsyncCalcQuest *quest)
    {
        //算了,不算这个了,根本算不出来
        quest->result = fibonacci(quest->num);       
        //quest->result = quest->num*0.618;
 
        //并将已完成任务返回到准备回调的列表
        std::unique_lock<std::mutex > lck(mutex_callbacks_);
        callbacks_.push_back(quest);
    }
 
    //在主线程执行
    void DoCallback()
    {
        //组回调任务上锁
        std::unique_lock<std::mutex > lck(mutex_callbacks_);
        while (!callbacks_.empty())
        {
            auto *quest = callbacks_.back();           
            {//此处为业务代码打印一下吧
                std::cout << quest->num << " " << quest->result << std::endl;
                now_count ++;
            }
            delete quest;       //TODO:这里如果采用内存池就更好了
            callbacks_.pop_back();
        }
    }
 
private:
    //这里是准备给回调的任务列表
    std::vector<AsyncCalcQuest*> callbacks_;
    std::mutex mutex_callbacks_;
};
 
int main()
{
    CalcWorkerPool workers;
 
    //工厂开工了 8个工人喔
    workers.Start(std::bind(&CalcWorkerPool::DoWork,&workers,std::placeholders::_1),8);
     
    //开始产生任务了
    for (int i=0; i<TOTAL_COUNT; i++)
    {
        AsyncCalcQuest *quest = new AsyncCalcQuest;
        quest->num = i%40+1;
        workers.Push(quest);
    }
 
    while (now_count != TOTAL_COUNT)
    {
        workers.DoCallback();
    }
 
    workers.Stop();
 
    return 0;
}



具有C ++ 11的跨平台网络库-C/C++开发 请参阅中文。请参见中文。Wiki简介CppNet是一种proactor模式和多线程网络,在tcp上具有C ++ 11。 很简单:只导出一点接口,所有的ios界面都是异步回调,一个中文。Wiki简介CppNet是一个proactor模式和tcp上具有C ++ 11的多线程网络。 简单:只导出一点接口,所有的net ios接口都是异步回调,就像调用系统的套接字API一样。 客户端只有一种附加的缓冲区对象类型。 快速:使用epoll和IOCP,其中epoll多线程线程由Linux内核通过端口重用进行处理。 每个插槽都有一个记忆 立即下载

相关推荐

ITK-snap医学图像标注方法(超级详细)——保姆级

医学3D图像标注方法,非常详细,保姆级

jialiyk的博客 3万+

C++ 11线程池

一、基本概念 1.1 为什么要用线程池 创建/销毁线程伴随着系统开销,过于频繁的创建和销毁线程会影响程序的处理效率: 如创建线程消耗时间为T1,执行任务消耗时间为T2,销毁线程消耗时间为T3,若T1+T3 > T2 ,则开启一个线程执行该任务不划算。 1.2 线程池的基本思想 因为程序边运行边创建线程是比较耗时的,所以我们通过池化的思想:在程序开始运行前创建多个线程,这样,程序在运行时,只需要从线程池中拿来用就可以了.大大提高了程序运行效率。 参考文献: https://b...

灰太狼的小秘密 8077

Aurora 8B/10B IP核介绍 —— Xilinx 技术文档Pg046

一、概述该IP核与用户接口之间支持AXI4-Stream协议,且基于ZYNQ SOC、A7、K7、V7以及UltraScale、UltraScale+系列FPGA的高速收发器(the high-speed serial transceivers)进行实现。多达 16 个连续绑定4 个连续绑定的 GTP 收发器framingstreaming以及全双工或单工加扰消扰CRC校验热插拔Aurora 8B/10B核心(图1-1)是一种可扩展的、轻量级的、用于高速串行通信的链路层协议;

qq_32147275的博客 1638

java de 线程池

线程池: java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池 作用:解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。 使用情况: 假设一个服务器完成一项任务所需时间为: T1 创建线程时间, T2 在线程中执行任务的时间, T3 销毁线程时间。 如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。 组成部分: ...

tayloramanda的博客 901

如何找回mysql删除的表_mysql误删表如何恢复,恢复被删除表的步骤说明

小编寄语想必大家都知道,Oracle ACE李真旭(Roger)是国内最专业的Oracle 数据库恢复专家。但知识都是触类旁通,真正的专家,从来不会局限在一个方向上。今天分享的内容,是他在MySQL数据恢复上所做的尝试。本文主要分享在没有备份的情况下,MySQL数据库如何恢复被删除的表。包含两个主要的场景:1、drop table后的恢复2、truncate table后的恢复正文:我们都知道,M...

weixin_35725389的博客 6783

【Linux】实际项目应该如何完成?--安防监控系统项目的总结

到目前为止我也做个5、6个嵌入式项目,但以往都是从零开始自己做,也就是毫无计划,想到那里做那里,有想法就会去实现,就这样导致我碰到了很多坑,也消耗了我许多时间,当然,不是说这样不好,因为在其中我也得到了一个很好的锻炼与练习,但是这不适用于在工作中去这样做。...

修成真的博客 6725

C++11实现线程池

C++11实现线程池

qq_42913081的博客 1128

8155平台multi-display(多屏显示)原理与配置

8155平台多屏互动原理与配置

漂流瓶の海岸 1606

基于C++11实现线程池

这篇总结会将重心放在C++11的语法糖上,对于C++11的并发编程部分(等)将仅进行最简洁最必要的阐述。

lingshengxiyou的博客 941

手把手教你用TL431设计反激电源补偿器(附波特图调试技巧)

本文详细介绍了如何使用TL431设计反激电源补偿器,并提供了波特图调试技巧。通过实战经验分享,帮助工程师快速掌握补偿网络设计、分压电阻计算和稳定性判据,避免常见设计误区,提升电源稳定性与效率。

weixin_29201859的博客 377

云桌面如何部署?云桌面系统方案部署详细教程

云桌面作为一种比较新的技术工具,核心解决的场景是方便设计师的灵活办公,本身技术就是非常的灵活性,所以在安装部署方面青椒云也做到了十足的灵活。

2301_79113726的博客 1633

运行后选择GDB/LLDB出现这样的窗口:launch: program ‘输入程序名称,例如 D:\Desktop\新建文件夹\a.exe‘ does not exist...如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 1127

【GitHub项目推荐--一个极快速的 C++ 日志库】【转载】

spdlog 极快速的 C++ 日志库。github地址非常快、仅标头/已编译的 C++ 日志库。

j8267643的博客 1137

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

基于 C++ POCO 库封装的异步多线程的 CHttpClient 类

用惯了 Jetty 的 基于事件的 HttpClient 类,在C++平台上也没找到这样调用方式的类库,只好自己写一个了。 目前版本 1.0,朋友们看了给点建议。(注:Kylindai原创,转载请注明出处) Feature: 基于C++跨平台的 POCO 库实现,支持线程池Poco::ThreadPool, 异步 HttpClient,支持Http事件回调处理。 基本思路,核心方法...

weixin_34081595的博客 577

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

C++多线程

condition_variable是一个类,这个类既有构造函数也有析构函数,使用时需要构造对应的condition_variable对象,调用对象相应的函数来实现上面的功能。优点:有操作系统相关知识的应该知道,线程是轻量级的进程,每个线程可以独立的运行不同的指令序列,但是线程不独立的拥有资源,依赖于创建它的进程而存在。简单地讲,unique_lock 是 lock_guard 的升级加强版,它具有 lock_guard 的所有功能,同时又具有其他很多方法,使用起来更加灵活方便,能够应对更复杂的锁定需要。

qq_45788429的博客 474

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【码云周刊第 41 期】C++ 网络编程初学者的开源项目

为什么80%的码农都做不了架构师?>>> ...

weixin_33972649的博客 242

[置顶] UILite——C++类库(XLib非界面功能库+UI和DirectUI库)简介

UILite是一款继承自WTL以及和界面无关的功能库的合集,能够生成很小的可执行文件。如果你也象我一样希望自己的程序又小又快的话,UILite就是你的选择。当然,我们还要克服一些障碍: 1)ATL/WTL样式的模板类初看起来有点怪异 2)没有类向导的支持,所以要手工处理所有的消息映射。 3)MSDN没有正式的文档支持,你现在看到的就是UILite的最权威的文档 4)买不到参考书籍...

weixin_30342827的博客 142

Cocos2dx 3.0 过渡篇(二十六)C++11多线程std::thread的简单使用(上)

昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:”看到前面那俩教练没?老色鬼两枚!整天调戏女学员。“她说:”还好啦,这毕竟是他们的乐趣所在,你不认为教练每天都教学员是非常枯燥的一件事么?所以调戏学员是他们每天的乐趣,这样工作才更有动力“。我承认听完她的话我愣住了!事后一夜没睡,总结出了两点:1、看待问题一定要从多个角度分析,别太主观,我认为他们是色鬼,难免会有妒忌的因素在里面(...

weixin_34349320的博客 108

11个Java 开源 socket框架

 Ice的Java版,Netty2作者的后续之作Apache MINA,Crmky的Cindy之外,还有个超简单的QuickServer,让你专心编写自己的业务代码,不用编写一行TCP代码。一、QuickServer 是一个免费的开源Java库,用于快速创建健壮的多线程、多客户端TCP服务器应用程序。使用QuickServer,用户可以只集中处理应用程序的逻辑/协议。二、Netty 2提供了一组基...

goldDaNiu的博客 9415

Java入门到精通-01 Java是什么?为什么学Java

Java是一种面向对象的跨平台编程语言,由Sun Microsystems于1995年推出,后被Oracle收购。其核心特性包括"一次编写,到处运行"的跨平台能力(通过JVM实现)、自动垃圾回收、丰富的API库和强大的企业级开发支持。Java广泛应用于企业级后端开发(90%财富500强公司使用)、移动开发(Android)、大数据处理(Hadoop)等领域。主要版本包括长期支持的LTS版本如Java 8、11、17和21。Java凭借其稳定性、安全性和庞大的开发者社区,30年来始终保持着主流编程语言的地位。

weixin_56693899的博客 1003

360春招Windows开发笔试核心考点全拆解

Windows系统开发历来要求开发者兼具C/C++功底与底层机制理解。从内存布局、结构体对齐到进程线程同步原语,每一项都直接关系到实际工程的稳定性与安全性。掌握内核对象、句柄表与PE结构等概念,是理解系统行为、排查程序异常的关键。在真实场景中,字符集编码转换常引发中文乱码,命令行脚本与批处理可提升自动化运维效率,驱动签名验证问题则影响设备兼容性。这些基础能力共同构成了客户端开发、安全软件研发等岗位的考察重点。本文以360春招Windows开发客观题为线索,系统梳理相关知识点与备考策略,帮助读者将零散经验串联

weixin_34226706的博客 376

我心目中的“商用化开发”和“工程化开发”征文 获奖名单

历时一个多月的“商用化开发”和“工程化开发”征文活动结束,经过各位评委评审,获奖名单终于出来了。获奖人和他们的参赛作品如下: 陈尚义 http://blog.youkuaiyun.com/shangyichen/archive/2009/11/23/4858650.aspx 马炳佳 http://blog.youkuaiyun.com/Beacher_Ma/...

weixin_30640291的博客 77

深度学习多机多卡解决方案-purine

未经允许请不要转载,原作者:zhxfl,http://www.cnblogs.com/zhxfl/p/5287644.html 目录: 一、简介 二、环境配置 三、运行demo 四、硬件配置建议 五、其他 一、简介 深度学习多机多卡集群已经成为主流,相对于caffe和mxnet这两个比较活跃的开源,purine显得更值得在高校的学生细读,因为purine的代码显得更加短小精悍...

weixin_33946605的博客 578
上一篇: 简单c++日志类
下一篇: Winsock完成端口模型(VER1)——I/O Completion Port(转载)
Syee001
博客等级 码龄14年 3粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值