std: atomic续谈、std: async深入谈
一 原子操作 std:atomic续谈
不是所有运算符都支持 比如不支持 a = a+1
二 std: async深入谈
2.1 std: async参数详述
std::thread() 如果系统资源紧张,可能会创建线程失败,执行std::thread()时程序可能会崩溃。
std::async 一般称之为创建一个异步任务,async有时并不创建新线程
如果用std::launch::deferred来调用async会怎么样,会延迟调用,并且不创建新线程,如果future不调用.wait或.get,则不执行async的入口函数
如果用std::launch::async 强制这个异步任务在新线程上执行,系统必须创建新线程。
std::launch::async |std::launch::deferred 当参数是这样时,意味着async的行为可能是其中任意一个,由编译器实现
当不传入参数时,默认参数为std::launch::async |std::launch::deferred,具体使用哪个由编译器控制。
#include <iostream>
#include <string>
#include <future>
#include <thread>
#include <mutex>
#include <atomic>
using namespace std;
int mythread()
{
cout<<"mythread start"<<"thread_id:"<<std::this_thread::get_id<<endl;
return 1;
}
int main()
{
cout<<"main thread_id:"<<std::this_thread::get_id<<endl;
std::future<int>result = std::async(std::launch::deferred,mythread);
cout<<result.get()<<endl;
cout<<"ok"<<endl;
return 0;
}
打印:
G:\CSlrn\C++Code\MultiThread\2_11\cmake-build-debug\2_11.exe
main thread_id:1
mythread startthread_id:1
1
ok
Process finished with exit code 0
2.2 std: async和std: thread的区别
- std::thread创建线程,如果系统资源紧张,创建线程失败,那么整个程序就会报异常并崩溃
- std::thread创建线程,如果线程有返回值,不方便拿到该返回值
- std::async创建异步任务,可能创建线程,也可能不创建线程,并且该方法很容易拿到线程入口函数的返回值。
由于系统资源限制 - (1)如果std::thread创建的线程太多,则可能创建失败,系统报告异常
- (2)std::async一般不会异常,如果系统资源紧张时,不加额外参数的async就不会创建新线程,而是后续谁调用了result.get来请求结果,那么这个异步任务就会运行在调用get语句的线程中执行。
- (3)一个程序里,线程数量不宜超过100-200
2.3 std async不确定性问题的解决
- 不加额外参数的std::async调用,让系统自行决定是否创建新线程
- 问题焦点:std::futureresult2 = std::async(mythread);这个写法
- 这个异步任务到底有没有被推迟执行 ,使用上节课的wait_for语句可以判断
int mythread()
{
cout<<"mythread start"<<"thread_id:"<<std::this_thread::get_id<<endl;
std::chrono::seconds dura(5);
std::this_thread::sleep_for(dura);
return 1;
}
cout<<"main thread_id:"<<std::this_thread::get_id<<endl;
std::future<int>result = std::async(std::launch::deferred,mythread);
std::future_status status = result.wait_for(std::chrono::seconds(2));
if (status == std::future_status::timeout)
{
//线程没有被推迟 但是还没执行完
cout<<"time out"<<endl;
}
else if (status == std::future_status::ready)
{
//线程没有被推迟,并且执行完了
cout<<"thread over"<<endl;
}
else if (status == std::future_status::deferred)
{
//线程被延迟了,需要由result.get()来启动线程
cout<<"thread deferred"<<endl;
result.get();
}
cout<<"ok"<<endl;
return 0;
G:\CSlrn\C++Code\MultiThread\2_11\cmake-build-debug\2_11.exe
main thread_id:1
thread deferred
mythread startthread_id:1
ok
Process finished with exit code 0
在代码调试中,当我们把额外参数设置为std::launch::async时,分别打印主线程id和子线程id,发现id是一样的,那么我们要判断是否启动了子线程,除了用wait_for函数来判断,我们还可以用延时语句来判断,比如下面这个例子
线程入口函数没延迟5s再打印线程id
int mythread()
{
std::chrono::seconds dura(5);
std::this_thread::sleep_for(dura);
cout<<"mythread start"<<"thread_id:"<<std::this_thread::get_id<<endl;
return 1;
}
main函数中,等待5s再执行reslut.get(),此时参数为deferred,可以预料到,当主线程等待5s后才会执行子线程,运行起来后,可以大概数一下秒数。
cout<<"main thread_id:"<<std::this_thread::get_id<<endl;
std::future<int>result = std::async(std::launch::deferred,mythread);
std::chrono::seconds dura(5);
std::this_thread::sleep_for(dura);
cout<<"result="<<result.get()<<endl;
cout<<"ok"<<endl;
return 0;
结果就是在打印完主线程id后,10s过后才会打印子线程id,打印reslut,打印ok,说明系统是没有创建子线程的。
G:\CSlrn\C++Code\MultiThread\2_11\cmake-build-debug\2_11.exe
main thread_id:1
mythread startthread_id:1
result=1
ok
Process finished with exit code 0
如果我们将参数改为std::launch::async,由std::launch::async的异步性可以知道,一创建std::async就会启动子线程,子线程内等待的5s和主线程内等待的5s几乎是同时开始计时的,所以总共只需要5s就会打印子线程id和reslut ,以及ok,我们就可以判断,std::launch::async确实创建了子线程
G:\CSlrn\C++Code\MultiThread\2_11\cmake-build-debug\2_11.exe
main thread_id:1
mythread startthread_id:1
result=1
ok
Process finished with exit code 0