C++11 推荐面向task编程

面向task任务编程, 而不是面向线程编程;

异步多线程的开发机制

  • std::thread
  • auto fut = std::async(doAsyncWork);

taskthread

  • get返回值, 就像调用普通函数一样; (返回值内存中存储); pthread_join也支持返回值, 不过要写的代码更多; std::thread没有办法获取;
  • get抛出异常, 可以在get捕获另一个线程堆栈抛出的异常; pthread_join也可; std::thread崩溃死亡, 进程也可能因此死亡;
  • 更加高层的抽象; 告别线程管理;

线程知识

  • 物理线程: 即核心数量, 超线程则多一个或多个硬件线程;
  • 软件线程: 即由操作系统抽象出来的; 轮流执行; 可多余硬件线程;
  • std::thread: 将软件线程handle封装; 更好的管理生命周期;

线程管理

资源超限导致创建失败

  • 一般由于线程数查过系统限制; ulimit -u 100再创建1024个线程就会触发;
#include<thread>
#include<vector>

int main() {
    std::vector<std::thread> a;
    for(int i = 0 ; i < 1024; i++)
	    a.emplace_back([](){while(1);});
}

执行结果

ch@ch-ubuntu:~/ch/cppfile/max_thread$ ulimit -u 100
ch@ch-ubuntu:~/ch/cppfile/max_thread$ ./a.out 
terminate called after throwing an instance of 'std::system_error'
  what():  Resource temporarily unavailable
Aborted (core dumped)
ch@ch-ubuntu:~/ch/cppfile/max_thread$ cat test.cpp 
#include<thread>
#include<vector>

int main() {
    std::vector<std::thread> a;
    for(int i = 0 ; i < 1024; i++)
	    a.emplace_back([](){while(1);});
}

规避超限方案一: 串行执行

问题是: 如果串行线程是UI线程, 会导致长期得不到响应而退出;

规避超限方案二: 等待线程销毁

但是如果所有线程都在等待这个即将新建的线程执行结果呢? (死锁)
比如: 条件变量之类的;

没有超限时可能存在的问题: 上下文切换

原因: 应用程序可执行数量超过硬件线程(核心);
cache miss: 即新核心缓存没有多少指令或数据在这个核心的cache中;
cache pollute: 新线程污染了cache, 之前的线程又切换到当前核心, 之前的都被污染了;
差不多一个意思;

如何规避频繁上下文切换

影响管理策略: 和调度, 线程变化负载, 切换一次开销, cpu cache, 跨平台适用性;

实在太麻烦了, 交给专业的C++标准库负责人来开发;std::async;

减少资源超限异常;
减少上下文切换;
std::aysnc不保证创建线程; 可能串行; 也可能并行; 即在future.get代码所在线程执行; 就像是a线程设置,b读取, 但是函数是在b执行的;

async不是万能的

async可以从系统的角度决策负载, 但是无法确定你的流程逻辑;
如果getUI线程, 同样会导致长期无法响应; 所以还是需要开发者在std管理负载的基础上自行修改逻辑;

std::launch::async强制创建线程;

线程池和负载均衡

前沿技术: 目前一些流行的线程池项目: 用系统级别线程池避免线程超限; 使用workstealing algorithms来达到负载均衡;

标准库: C++11因为很多并发标准,使得上面的很难实现; 但是有的标准库提供者实现了(gnu, clang, others);

std::async: 如果你用了, 可能会用到最前沿的技术; 如果没用, 也和std::thread持平; 反正不亏;

std::thread: 自行管理, 不一定有人家做得好; 而且花很多时间; 而且需要高度定制; 建议自行尝试, 不用总是拿来主义, 小心被卡脖子;

对比

task based

  • 不用线程管理;
  • 有返回值;

std::thread

  • 更加精细的控制; 获取底层API, 进行更加定制化的操作; 优先级, 堆栈, 等等属性;
  • 特定环境调优: 比如根据某个操作系统定制化其特定的线程调度策略进行调优;
  • 线程池: 前面说了有的std::async底层没用线程池; 这时候就需要自己实现;

注: 通用可以提高效率, 但是不能提升性能; 因为需要通用;

总结

std::thread无返回值, 异常不友好(简介导致崩溃);

std::thread需要自行管理调度和负载均衡;

std::async解决大多数问题; 并不能解决所有问题;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值