task
任务编程, 而不是面向线程编程;std::thread
auto fut = std::async(doAsyncWork);
task
比thread
好get
返回值, 就像调用普通函数一样; (返回值内存中存储); pthread_join
也支持返回值, 不过要写的代码更多; std::thread
没有办法获取;get
抛出异常, 可以在get
捕获另一个线程堆栈抛出的异常; pthread_join
也可; std::thread
崩溃死亡, 进程也可能因此死亡;std::thread
: 将软件线程handle
封装; 更好的管理生命周期;ulimit -u 100
再创建1024
个线程就会触发;#include
#include
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
#include
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
可以从系统的角度决策负载, 但是无法确定你的流程逻辑;
如果get
是UI
线程, 同样会导致长期无法响应; 所以还是需要开发者在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
解决大多数问题; 并不能解决所有问题;