文档章节

Multi thread: std::shared_future(2)

SHIHUAMarryMe
 SHIHUAMarryMe
发布于 2016/05/13 15:44
字数 776
阅读 112
收藏 0

在之前我们了解到std::future,但是通过class std::future获得的结果只能get()一次,第二次调用通常会抛出一个std::future_error。

但是当多个其他线程想处理另外一个线程的结果的时候,也就是需要多次get(),基于这个目的C++ standard library提供了 std::shared_future,于是我们就可以多次调用get(),拿到相同的结果,或者抛出(throw)同一个异常.

std::shared_future相对于std::future来说只是少了一个share()操作.别的操作基本上是与 std::future一致的.此外还有以下几点不同:

1, std::future是不能被拷贝的(但是需要注意的是std::fututre和std::shared_future一样都是支持move的).

2, std::shared_future可以多次调用get().

3, std::future可以通过std::future::shared()获得一个std::shared_future(当然这会导致std::future无效).

 

 

我们来看一个例子吧:

#include <iostream>
#include <future>
#include <thread>
#include <exception>
#include <stdexcept>

int queryNumber()
{
	std::cout << "enter a number: ";
	int number;
	std::cin >> number;

	if (!std::cin) {
		throw std::runtime_error(std::string("no number read!"));
	}

	return number;
}

void doSomething(const char& c, const std::shared_future<int>& f)
{
	try {
		int number = f.get();

		for (int i = 0; i < number; ++i) {
			std::this_thread::sleep_for(std::chrono::duration<int, std::ratio<1, 1000>>(1));
			std::cout.put(c).flush();
		}

	}catch (const std::exception& e) {
		std::cerr << "EXCEPTION in thread" << std::this_thread::get_id() << ": " << e.what() << std::endl;
	}
}

int main()
{
	try {
		std::shared_future<int> result = std::async(std::launch::async, queryNumber);
		
		std::future<void> result1 = std::async(std::launch::async, doSomething, '.', result); 
		//注意我们在std::async()中传递的参数result其实是对result的拷贝.
		//如果我们写成std::async(std::launch::async, '.', std::ref(result));这种情况下才是对result的引用.
		//这样一来就是对一个std::shared_future多次调用get()了.于是就带来了风险.
		std::future<void> result2 = std::async(std::launch::async, doSomething, '+', result);
		std::future<void> result3 = std::async(std::launch::async, doSomething, '*', result);

		result1.get();
		result2.get();
		result3.get();

	}catch (const std::exception& e) {
		std::cout << "\nEXCEPTION: " << e.what() << std::endl;
	}

	std::cout << "\ndone" << std::endl;

	return 0;
}

std::async与传递实参到callable object

首先来看一个例子:

#include <iostream>
#include <thread>
#include <chrono>
#include <future>
#include <random>

void doSomething(const char& c)
{
	std::default_random_engine engine(c);
	std::uniform_int_distribution<int> distribution(10, 100);

	for (int i = 0; i < 10; ++i) {
		std::this_thread::sleep_for(std::chrono::milliseconds(distribution(engine)));
		std::cout.put(c).flush();
	}
}

int main()
{
	std::cout << "starting 2 operation asynchronously" << std::endl;
	std::future<void> result1(std::async([]() { doSomething('.'); }));
	std::future<void> result2(std::async([]() { doSomething('+'); }));

	//下面首先检查是否被推迟调用了.
	if (result1.wait_for(std::chrono::seconds(0)) != std::future_status::deferred || result2.wait_for(std::chrono::seconds(0)) != std::future_status::deferred) {

        //循环检测std::future中的shared state是否被设置好了.
		while (result1.wait_for(std::chrono::seconds(0)) != std::future_status::ready && result2.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
			std::this_thread::yield();
		}
	}

	std::cout.put('\n').flush();

	try {
		result1.get();
		result2.get();

	}catch (const std::exception& e) {
		std::cout << "\nEXCEPTION: " << e.what() << std::endl;
	}

	std::cout << "\ndone" << std::endl;

}

在上面的例子中我们都是by-value(拷贝)的形式传值进去callable object.

如果是by-reference:

char c = '@';
std::future<void> result3 = std::async([&](){ doSomething(c); });

//或者是:
std::future<void> result4 = std::async(doSomething, std::ref(c));
//注意上面的std::ref;

这样一来就产生了data-race(数据竞争),而且如果其中的一个线程修改了c的值,另外一个线程可能出来的结果就不是我们先要的了.因此最好还是by-value的形式传值进去.

© 著作权归作者所有

共有 人打赏支持
SHIHUAMarryMe
粉丝 12
博文 163
码字总数 137779
作品 0
武汉
程序员
Multi thread: std::promise

前面我们了解到可以使用std::sharedfuture/std::sharedfuture在多个其他线程中处理另外一个线程的函数的返回结果. 那么疑问来了,我们要怎样在多线程之间传递数据呢? demo1 :std::promise在线...

SHIHUAMarryMe
2016/05/14
80
0
Multi thread: std::async()和std::future(1)

对于初学者而言,“以多线程运行程序”的最佳起点就是C++标准库中的 std::async() 和 class std::future提供的高级接口. (1),std::async()提供一个接口,让一段机能或者说一个callable obje...

SHIHUAMarryMe
2016/05/10
292
0
C++11: std::packaged_task

class std::packaged_task被用来同时存储callable object,以及该callable object的返回值(也可能是个异常). ----------------------------我是分割线------------------------------ std:......

SHIHUAMarryMe
2016/05/15
93
0
C++11实现跨平台线程池

生产者消费者 转自:http://www.cnblogs.com/sanjin/archive/2012/08/09/2629890.html std::conditionvariable的使用方法如下: ·当持有锁(mutex)之后,线程调用wait ·wait解开持有的互斥锁...

初雪之音
2016/03/19
376
0
shared_ptr 的使用及注意事项

1. 声明 #include class UsersBitmap { ... } typedef boost::shared_ptr UsersBitmapPtr; 2. 使用 UsersBitmapPtr loginusers; UsersBitmapPtr temploginusers(new UsersBitmap()); //指向对......

xumaojun
03/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

SpringCloud SpringBoot mybatis分布式Web应用的统一异常处理

我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况。Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用...

itcloud
21分钟前
0
0
c++ std::bind和std::function

定义于头文件 <functional> std::bind 函数绑定,https://zh.cppreference.com/w/cpp/utility/functional/bind // bind 用例#include <iostream>#include <functional> // 自定义的一......

SibylY
24分钟前
0
0
SecureCRT的安装与破解(过程很详细!!!)

SecureCRT的安装与破解(过程很详细!!!) SecureCRT的安装与破解(过程很详细!!!) 使用SecureCRT可以方便用户在windows环境下对linux主机进行管理,这里为大家讲一下SecureCRT的破解方...

DemonsI
28分钟前
0
1
介绍几款可用的web应用防火墙

目前有两款,基于软件和基于应用程序的web应用防火墙。基于软件的产品布置在Web服务器上,而基于应用程序的产品放置在Web服务器和互联网接口之间。两种类型的防火墙都会在数据传入和传出web...

上树的熊
35分钟前
1
0
用Visual Studio开发以太坊智能合约

区块链和以太坊 自从我熟悉区块链、以太坊和智能合约以来,一直失眠。 我一直在阅读,阅读和阅读,最后我能够使用一些工具,他们建议使用以太坊网站官方客户端应用程序(Ethereum Wallet)也...

geek12345
37分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部