首页 > 编程语言 >C++之future

C++之future

时间:2023-07-08 11:23:14浏览次数:52  
标签:std 异步 C++ future promise result 操作

背景

在C++多线程编程中,同步线程间的操作和结果通常是一个关键问题。C++11引入了std::future这一同步原语,用于表示异步操作的结果。本文将介绍C++中std::future的使用方法、优势以及与其他同步方法的对比。

使用std::future

std::future表示一个异步操作的结果,可以用于获取操作的返回值或者等待操作完成。std::future通常与std::async、std::packaged_task或std::promise一起使用。

使用std::async

std::async是一个简单的异步操作启动器,它接受一个函数及其参数,并在一个新线程中执行该函数。std::async返回一个std::future对象,用于表示异步操作的结果。

#include <iostream>
#include <future>
#include <chrono>

int slow_operation() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return 42;
}

int main() {
    std::future<int> result = std::async(slow_operation);
    std::cout << "Waiting for the result..." << std::endl;
    int value = result.get();
    std::cout << "Result: " << value << std::endl;
    return 0;
}

在这个示例中,我们使用std::async启动一个慢速操作slow_operation。std::async返回一个std::future对象,我们可以使用get()方法等待操作完成并获取结果。

使用std::packaged_task

std::packaged_task是一个通用的异步操作包装器,它接受一个函数并将其包装成一个任务。我们可以将任务传递给一个线程执行,然后使用std::future来表示任务的结果。

#include <iostream>
#include <future>
#include <thread>

int slow_operation() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return 42;
}

int main() {
    std::packaged_task<int()> task(slow_operation);
    std::future<int> result = task.get_future();
    std::thread t(std::move(task));
    std::cout << "Waiting for the result..." << std::endl;
    int value = result.get();
    std::cout << "Result: " << value << std::endl;
    t.join();
    return 0;
}

在这个示例中,我们使用std::packaged_task包装一个慢速操作slow_operation,然后将任务传递给一个线程执行。我们使用get_future()方法获取一个std::future对象,用于表示任务的结果。

使用std::promise

std::promise是一个低级别的异步操作同步原语,它允许我们在一个线程中设置操作的结果,并在另一个线程中等待该结果。std::promise与std::future一起使用,用于表示操作的结果。

#include <iostream>
#include <future>
#include <thread>

void slow_operation(std::promise<int> result_promise) {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    result_promise.set_value(42);
}

int main() {
    std::promise<int> result_promise;
    std::future<int> result = result_promise.get_future();
    std::thread t(slow_operation, std::move(result_promise));
    std::cout << "Waiting for the result..." << std::endl;
    int value = result.get();
    std::cout << "Result: " << value << std::endl;
    t.join();
    return 0;
}

在这个示例中,我们使用std::promise在slow_operation函数中设置操作的结果。我们使用get_future()方法获取一个std::future对象,用于表示操作的结果。

std::future的优势

相较于其他同步方法,如互斥锁(std::mutex)和条件变量(std::condition_variable),std::future具有以下优势:

  • 简化编程模型:std::future简化了线程间结果传递的编程模型,使得我们可以更容易地编写正确的并发代码。
  • 自动同步:std::future在获取结果时自动实现同步,无需显式地使用互斥锁或条件变量。
  • 异常安全:std::future可以在异步操作中捕获异常,并在获取结果时重新抛出,从而确保异常安全。

使用场景与比较

std::future适用于以下场景:

  • 需要在线程间传递结果的异步操作。

  • 需要等待异步操作完成的场景。

  • 需要捕获异步操作中的异常。 相较于其他同步方法,std::future具有更简洁的编程模型和更好的异常安全性。然而,在某些场景下,互斥锁和条件变量可能更适合,例如:

  • 需要保护复杂数据结构的访问。

  • 需要在线程间传递通知的场景(如生产者消费者队列)。

最后

总结一下,在这篇博客中,我们介绍了C++并发操作同步中的std::future,包括使用std::async、std::packaged_task和std::promise进行异步操作,以及std::future的优势和使用场景。std::future是一种强大的同步原语,可以帮助我们简化多线程编程中的同步问题。在实际应用中,我们需要根据具体的需求和场景选择合适的同步方法,以实现高效、稳定的多线程程序。

标签:std,异步,C++,future,promise,result,操作
From: https://www.cnblogs.com/blizzard8204/p/17536939.html

相关文章

  • C++之条件竞争
    背景在多线程编程中,线程间共享数据是一种常见的情况。然而,如果不加以处理,共享数据可能导致一些问题,如条件竞争。在这篇博客中,我们将介绍C++线程共享数据的问题,包括条件竞争的概念以及防止恶性条件竞争的方法。什么是条件竞争?条件竞争(RaceCondition)是指多个线程在访问和操作共......
  • C++之共享数据
    背景在C++多线程编程中,线程间共享数据是一种常见的情况。然而,如果不加以处理,共享数据可能导致一些问题,如条件竞争。本文将介绍C++中多线程共享数据的方式,包括各种方式的使用场景和比较。使用互斥锁(Mutex)互斥锁(Mutex)是一种同步原语,用于保护共享数据的访问。当一个线程访问共享数......
  • C++之死锁
    背景在多线程编程中,死锁是一个常见的问题,它会导致程序陷入无法继续执行的状态。在这篇博客中,我们将介绍C++中死锁的概念、产生原因以及解决办法。什么是死锁?死锁是指多个线程在等待对方释放资源,导致彼此都无法继续执行的情况。死锁通常发生在多个线程同时锁定多个互斥锁的情况......
  • C++之线程管控(一)
    背景多线程编程在实际应用中非常常见,它可以帮助我们提高程序性能,实现高效的任务调度。从C++11开始,C++语言已经提供了对多线程编程的原生支持。本文将详细介绍如何使用C++进行线程管控,包括发起线程、等待线程完成、异常处理以及在后台运行线程等内容。发起线程C++11提供了一个名......
  • C++之线程管控(二)
    背景随着多核处理器的普及,多线程编程已经成为软件开发中不可或缺的一部分。C++11标准为我们带来了线程库,让我们能够更方便地在C++中实现多线程编程。在这篇博客中,我们将介绍C++线程管控的基本概念和方法,包括向线程函数传递参数,移交线程归属权,运行时选择线程数量和识别线程。向线......
  • C++ Primer 学习笔记——第七章
    第七章类前言基本数据类型有时候并不能解决某些特定问题,而通过自定义的类就可以通过理解问题概念,使得程序更加容易编写、调试和修改。类的基本思想是数据抽象(dataabstraction)和封装(encapsulation)。数据抽象是一种依赖于接口(interface)和实现(implementation)分离的编程(以及设......
  • c++ 科幻版 沙漠神殿2
    #include<iostream>#include"minecraft.h"#include<string>usingnamespacestd;TxMinecraftmc;intx,y,z;boolcon;boollianjie(){ returncon=mc.ConnectMinecraft("mc.makeblock.net.cn","a9d44e758f6e4cf8b2da26241......
  • 请使用C++计算出2^2023与3^2023的和
    易知,这个和的数字是非常大的,大到longlong都装不下,这个时候如果使用longlong是无法进行运算的。欸!这会高精度算法(即大数运算)就开始发光发热了。以下是我看资料总结的一些歪瓜裂枣。对于一位高精度数字,用整数数组存储,数组每一个元素对应一位十进制数,由其下标顺序指明位序号......
  • 别再问我Runnable、Callable、Future、FutureTask有什么关联了
    Runnable与Callable众所周知,当我们使用线程来运行Runnable任务时,是不支持获取返回值的,因为Runnable接口的run()方法使用void修饰的,方法不支持返回值。而在很多场景下,我们一方面需要通过线程来异步执行任务,以便提升性能,另一方面还期望能获取到任务的执行结果。尤其是在RPC框架中,异......
  • c++沙漠神殿
    #include<iostream>#include"minecraft.h"#include<string>usingnamespacestd;TxMinecraftmc;intx=0,y=0,z=0;intmain(intargc,char**argv){boolcon=mc.ConnectMinecraft("zk.makeblock.net.cn","a9d44e758f6e4cf8b......