std::atomic、std::async深入研究
1.从上节课的一个demo说起。
#include <iostream>
#include <future>
#include <vector>
#include <atomic>
#include <thread>
using namespace std;
std::atomic<int> g_mycount(0);
void mythread()
{
for (int i = 0; i < 1000000; i++)
{
//g_mycount++; //ok
//g_mycount+=1; //ok
g_mycount=g_mycount+1; //error
}
return;
}
int main()
{
cout << "int main(),beign,thread id=" << this_thread::get_id() << endl;
thread mytobj1(mythread);
thread mytobj2(mythread);
mytobj1.join();
mytobj2.join();
cout << "两个线程执行完毕,最终:g_mycount=" << g_mycount << endl;
cout << "I Love China!" << endl;
return 0;
}
//g_mycount++; //ok
//g_mycount+=1; //ok
g_mycount=g_mycount+1; //error 为什么这样写,不行???得出的结果不是我们最终想要的结果呢?
因为,一般atomic原子操作,针对++,--,+=,&=,|=,^= 等是支持的。其他的可能不支持。
std::async深入研究
std::async参数研究 。
std::async用来创建一个异步任务。
1.参数 launch::async【强制创建一个新线程】,launch::deferred【延迟调用,并且不创建新线程】
2.std::thread() 如果系统资源紧张,那么可能创建线程就会失败,那么执行std::thread()时候整个程序就会崩溃。
3.std::async 和 std::thread 最明显的不同是,就是async有时候并不创建新线程。(而是直接在调用get()出的线程入口函数。)
#include <iostream>
#include <future>
#include <vector>
#include <atomic>
#include <thread>
using namespace std;
std::atomic<int> g_mycount(0);
int mythread()
{
cout<<"int mythread() start "<<" threadid = "<<std::this_thread::get_id()<<endl;
return 1;
}
int main()
{
cout<<"int main() start "<<" threadid = "<<std::this_thread::get_id()<<endl;
std::future<int> result = std::async(std::launch::deferred,mythread);
//std::launch::deferred 用这个参数代表的意义是:std::async 线程需要等到(本质就是延迟到)后续调用 get() 或者 wait()的时候,才会执行std::async(std::launch::deferred,mythread);
//如果后续没有调用wait() 或者 get() 那么std::async 就不会创建一个新线程。
cout<<result.get()<<endl;
cout << "I Love China!" << endl;
return 0;
}
输出结果:线程pid都是一样的,std::async 并没有创建新线程。
int main() start threadid = 139694322440000
int mythread() start threadid = 139694322440000
1
I Love China!
c)std::launch::async|std::launch::deferred 意义是:意味着调用async的行为,或者调用 deferred的行为,这两者局其一。
d) 当没有指定额外参数的时候,其实,默认值应该是:std::launch::async|std::launch::deferred,和 c) 效果一致的。系统会自行决定是异步运行 还是 同步运行。
二、std::async 和 std::thread 的区别
std::thread() 如果系统资源紧张,那么可能创建线程就会失败,那么执行std::thread()时候整个程序就会崩溃。
int mythread(){return 1;}
std::thread mytobj(mythread);
mytobj.join()
类型上述的代码,
1.通过std::thread()方式创建的线程,如果想得到线程的返回值,那么不太容易操作。需要保存到一个全局变量中。
2.std::async创建异步任务。可能创建也可能不创建。并且async调用方法很容易拿到线程入口函数的返回值。
由于系统资源限制:
1.如果用std::thread 创建的线程太多,则可能会创建失败,系统报告异常,崩溃。
2.如果用std::async,一般不会报告异常,不会崩溃。因为,如果系统资源紧张导致无法创建新线程的时候,std::async 这种不加额外参数的调用(std::launch::async|std::launch::deferred) 就不会创建新线程,而是后续谁调用了 result.get()来请求结果。那么这个异步任务就运行在执行这条get()语句所在的线程上。
3.如果你强制std::async一定要创建新线程,那么就必须用std::lunch::async。承受的代价是系统资源紧张时,程序崩溃。
4.经验:一个程序里,线程数量不宜超过 100-200个,时间片。
std::async 不确定性问题的解决
1.不加额外参数的std::async调用,让系统自行决定是否创建新线程。问题的焦点在于:std::future<int> result = std::async(mythread) ;写法。这个异步任务到底有没有被推迟执行?(std::launch::async 还是 std::launch::deferred)
2.想要解决这个问题,需要利用std::future对象的wait_for 函数。
future_status::timeout 和 future_status::ready 这两种转态是创建了新线程,而future_status::deferred 这一种状态是没有创建新线程。
想判断async到底有没有创建新线程立即执行,还是延迟(没有新建线程)执行。
#include <iostream>
#include <future>
#include <vector>
#include <thread>
#include <chrono>
using namespace std;
int mythread()
{
cout << "int mythread() start,thread id=" << std::this_thread::get_id() << endl;
chrono::milliseconds dura(5000);
this_thread::sleep_for(dura);
cout << "int mythread() end,thread id=" << std::this_thread::get_id() << endl;
return 5;
}
int main()
{
cout << "int main(),beign,thread id=" << this_thread::get_id() << endl;
//future<int> result = async(std::launch::deferred,mythread); //launch::deferred 不会创建子线程,是和主线程是一个线程
future<int> result = async(mythread);
cout << "continue...!" << endl;
//cout << result.get() << endl;
future_status status = result.wait_for(chrono::seconds(0));
if(status == future_status::deferred)
{
//
cout<<result.get()<<endl;
}
else
{
if (status == future_status::timeout) //超时:表示线程还没执行完,希望1秒钟内就返回,但是没有返回,此时就会超时;
{
cout << "超时了,线程还没有执行完." << endl;
}
else if (status == future_status::ready)
{
cout << "表示线程成功返回了." << endl;
cout<<result.get()<<endl;
}
}
cout << "I Love China!" << endl;
return 0;
}

浙公网安备 33010602011771号