• C++ 11 多线程之future


    什么是std::future?

    在C++ 11中std::future是一个绕不开的新特性,因为他的引入极大提高了大家编码的效率。std::future是一个类模板,它将存放着一个未来的变量,而这个变量可以通过std::future提供的成员函数std::future::get()来得到。

    std::future从何而来?

    std::future通常可以通过调用函数(provider)来构造对象,provider一般指std::async、std::promise、std::packaged_task

    • std::async 函数
    • std::promise::get_future:get_future 为 promise 类的成员函数
    • std::packaged_task::get_future: get_future为 packaged_task 的成员函数

    如果std::future这个变量尚未被赋值之前,就有其他线程试图通过std::future::get()获取这个变量,那么这个调用std::future::get()线程将会被阻塞到这个变量可以获取为止,才会继续执行。

    std::future的构成

    在这里插入图片描述

    • 基础函数(构造、析构、赋值):
      std::future 的拷贝构造函数是被禁用的,只提供了默认的构造函数和移动构造函数。另外,std::future的赋值构造函数禁用,只提供了 move 赋值操作

    • share函数:获取共享的future,返回一个std::shared_future对象,该对象获取future对象的共享状态。future对象将不再有效。

    • valid函数:检查共享状态的有效性,返回当前的future对象是否与共享状态关联。一旦调用了std::future::get()函数,再调用此函数将返回false。

    • wait函数:等待共享状态就绪,如果共享状态尚未就绪(即提供者尚未设置其值或异常),则该函数将阻塞调用者的线程直至共享状态就绪后,该函数将取消阻塞并void返回。

    • wait_for函数:等待共享状态在指定的时间内(时间片)准备就绪,如果同样尚未就绪,则该函数将阻塞调用者的线程直到就绪或已达到设置超时的时间。
      此函数的返回值类型为枚举类future_status。

      • ready:共享状态已就绪或者异常;
      • timeout:在规定的时间内未就绪;
      • deferred:异步函数操作还没开始;
    • wait_until函数:等待共享状态在指定的时间点(时间点)准备就绪,如果同样尚未就绪,则该函数将阻塞调用者的线程直到就绪或已达到设置超时的时间。
      此函数的返回值类型为枚举类future_status,具体释义同上

    代码释义
    #include 
    #include 
    #include 
    using namespace std;
    namespace {
    	
    	int TestFunc(int x)
    	{
    		cout << "thread id=" << std::this_thread::get_id() << endl;
    		int result = 0;
    		for (int i = 0; i < x; i++) {
    			result += 3;
    			std::this_thread::sleep_for(std::chrono::milliseconds(100));
    		}
    		return result;
    	}
    } // namespace
    void Test_share()
    {
    	std::future<int>        ret_data        = std::async([] { return 50; });
    	std::shared_future<int> shared_ret_data = ret_data.share();
    	try {
    		// share()后,ret_data对象将变得无效,调用空指针
    		std::cout << "ret_data valid: " << ret_data.valid() << endl;
    		std::cout << "ret_data get: " << ret_data.get() << endl;
    
    	} catch (const std::future_error& e) {
    		// exception: std::future_error
    		std::cout << "future_error : " << e.what() << std::endl;
    	}
    	//std::shared_future对象,get函数可以被多次访问
    	std::cout << "value: " << shared_ret_data.get() << endl;
    	std::cout << "its double: " << shared_ret_data.get() * 2 << endl;
    }
    void Test_valid_get()
    {
    	std::future<int> ret_data = std::async([] { return 50; });
    	cout << ret_data.valid() << endl;//获取有效性
    	cout << ret_data.get() << endl; //first get
    	cout << ret_data.valid() << endl;//获取有效性
    	try {
    		std::cout << "ret_data get: " << ret_data.get() << endl; // second get
    	} catch (const std::future_error& e) {
    		// exception: std::future_error
    		std::cout << "future_error : " << e.what() << std::endl;
    	}
    }
    void Test_wait()
    {
    	cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
    	std::future<int> ret_data = std::async(TestFunc, 5);
    	std::cout << "wait..." << endl;
    	ret_data.wait();
    	std::cout << "ready..." << endl;
    	std::cout << "ret_data get: " << ret_data.get() << endl; // second get
    }
    void Test_wait_()
    {	
    	/*
    	enum class future_status { // names for timed wait function returns
        ready,
        timeout,
        deferred
    	};
    	*/
    	int call_sum = 0;
    	while (cin >> call_sum) {
    		cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
    		std::future<int> ret_data = std::async(TestFunc, call_sum);
    		std::cout << "wait start" << endl;
    		std::chrono::milliseconds span(200);
    		std::future_status        ret_state = ret_data.wait_for(span);//获取状态
    		//std::future_status        ret_state =
    		//	ret_data.wait_until(std::chrono::system_clock::now() + std::chrono::milliseconds(200)); //获取状态,200ms后
    		std::cout << "wait end state=" << static_cast<int>(ret_state) << endl;
    		try {
    			std::cout << "ret_data get: " << ret_data.get() << endl; // second get
    		} catch (const std::future_error& e) {
    			// exception: std::future_error
    			std::cout << "future_error : " << e.what() << std::endl;
    		}
    	}	
    }
    int main()
    {
    	Test_share();
    	cout << "======================================================" << endl;
    	Test_valid_get();
    	cout << "======================================================" << endl;
    	Test_wait();
    	cout << "======================================================" << endl;
    	Test_wait_();
    	cout << "======================================================" << endl;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    结果
    在这里插入图片描述
    在这里插入图片描述

    引申std::shared_future

    std::shared_future 与std::future接口基本一致。

    与std::shared_future关系
    • std::shared_future对象可以通过std::future对象进行隐式转换,也可以通过显示调用std::future::share显示转换,在这两种情况下,原来的std::future对象都会无效。
    • 当你需要具有std::future的多个有效拷贝时会用到std::shared_future;或者多个使用者使用std::future时也会用到std::shared_future
    主要在用法上有区别
    • 支持copy(拷贝构造函数,拷贝赋值操作);
    • get()是一个const成员函数,返回一个const reference指向“存储于shared state”的值,通过shared_future::get检索的值不会释放共享对象的所有权
    • 共享状态(shared state)的生存期至少要持续到与之关联的最后一个对象被销毁为止。

    参考连接:future实现

  • 相关阅读:
    亚洲国家列表 Asia country list
    【共读】企业信息安全建设与运维指南(二)
    【源码】第10期|configstore 持久化配置存储
    LLM 大语言模型学习笔记
    juc并发编程
    Docker部署SpringBoot项目
    [H5动画制作系列]代码画图
    DNS配置
    Android 使用adb操作WiFi相关指令
    关于Docker中设置Java应用的JVM
  • 原文地址:https://blog.csdn.net/u013052326/article/details/126922604