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;
}

posted @ 2022-12-15 15:49  repinkply  阅读(105)  评论(0)    收藏  举报