C++并发与多线程(四)async、future、packaged_task、promise、shared_future(下)

简介: C++并发与多线程(四)async、future、packaged_task、promise、shared_future(下)

packaged_task包装起来的可调用对象还可以直接调用,从这个角度来讲,packaged_task对象也是一个可调用对象,lambda的直接调用。

#include <iostream>
#include <future>
using namespace std;
int main(){
    cout << "main started and the thread id is " << std::this_thread::get_id() << endl;
    //我们把函数mythread通过packaged_task包装起来。参数是一个int,返回值类型是int
    std::packaged_task<int(int)> mypt([](int num){
        cout << "mythread() started and the thread id is " << std::this_thread::get_id() << endl;
        cout << "num is: " << num << endl;
        std::chrono::milliseconds dura(5000); // 休息五秒
        std::this_thread::sleep_for(dura);
        cout << "mythread() ended and the thread id is " << std::this_thread::get_id() << endl;
        return 5;
    });
    mypt(10);
    //std::thread mythread(std::ref(mypt), 10); // 线程直接开始执行,第二个参数为线程入口参数
    //mythread.join();
    //std::future对象里包含有线程入口函数的返回结果,这里result保存mythread返回的结果。
    std::future<int> res = mypt.get_future();
    cout << "res.get() is : " << res.get() << endl;
    cout << "main ended and the thread id is " << std::this_thread::get_id() << endl;
}

  还有一些加容器的骚操作:

#include <iostream>
#include <future>
#include <vector>
using namespace std;
vector<std::packaged_task<int(int)>> mytask;
int main(){
    cout << "main started and the thread id is " << std::this_thread::get_id() << endl;
    //我们把函数mythread通过packaged_task包装起来。参数是一个int,返回值类型是int
    std::packaged_task<int(int)> mypt([](int num){
        cout << "mythread() started and the thread id is " << std::this_thread::get_id() << endl;
        cout << "num is: " << num << endl;
        std::chrono::milliseconds dura(5000); // 休息五秒
        std::this_thread::sleep_for(dura);
        cout << "mythread() ended and the thread id is " << std::this_thread::get_id() << endl;
        return 5;
    });
    mytask.push_back(std::move(mypt)); // 入容器,用了移动语意。
    std::packaged_task<int(int)> mypt2;
    auto iter = mytask.begin();
    mypt2 = std::move(*iter); // 移动语意。
    mytask.erase(iter); // 删除第一个元素,后续代码已经不可以再使用iter了。
    mypt2(10);
    std::future<int> res = mypt2.get_future();
    cout << "res.get() is : " << res.get() << endl;
    cout << "main ended and the thread id is " << std::this_thread::get_id() << endl;
}

  程序输出结果为:

main started and the thread id is 0x1000e3d40
mythread() started and the thread id is 0x1000e3d40
num is: 10
mythread() ended and the thread id is 0x1000e3d40
res.get() is : 5
main ended and the thread id is 0x1000e3d40
Program ended with exit code: 0

std::promise

  std::promise,也是一个类模板,功能是:我们能够在某个线程中给它赋值,然后我们可以在其他线程中,把这个值取出来

#include <iostream>
#include <future>
#include <vector>
using namespace std;
void mythread(std::promise<int> &tmp, int calc){
    cout << "mythread() started and the thread id is " << std::this_thread::get_id() << endl;
    std::chrono::milliseconds dura(5000); // 休息五秒
    std::this_thread::sleep_for(dura);
    ++calc; // 假装有复杂的计算
    tmp.set_value(calc);
    cout << "mythread() ended and the thread id is " << std::this_thread::get_id() << endl;
}
int main(){
    cout << "main started and the thread id is " << std::this_thread::get_id() << endl;
    std::promise<int> myprom;
    std::thread t1(mythread, std::ref(myprom), 10);
    t1.join();
    std::future<int> res = myprom.get_future(); // future和promise绑定在一起。
    cout << "res.get() is : " << res.get() << endl;
    cout << "main ended and the thread id is " << std::this_thread::get_id() << endl;
}

  输出结果为:

main started and the thread id is 0x1000dfd40
mythread() started and the thread id is 0x16fe87000
mythread() ended and the thread id is 0x16fe87000
res.get() is : 11
main ended and the thread id is 0x1000dfd40
Program ended with exit code: 0
• 1
• 2
• 3
• 4
• 5
• 6

  总结:通过promise保存一个值,在将来某个时刻我们通过吧一个future绑定到这个promise上,来得到绑定的值。如果想把线程1中的值传入到线程2中去的话,可以采用如下方式:

#include <iostream>
#include <future>
#include <vector>
using namespace std;
void mythread(std::promise<int> &tmp, int calc){
    cout << "mythread() started and the thread id is " << std::this_thread::get_id() << endl;
    std::chrono::milliseconds dura(5000); // 休息五秒
    std::this_thread::sleep_for(dura);
    ++calc; // 假装有复杂的计算
    tmp.set_value(calc);
    cout << "mythread() ended and the thread id is " << std::this_thread::get_id() << endl;
}
void mythread_other(std::future<int> &tmp){
    cout << "mythread_other() started and the thread id is " << std::this_thread::get_id() << endl;
    std::chrono::milliseconds dura(5000); // 休息五秒
    std::this_thread::sleep_for(dura);
    cout << "mythread_other tmp.get() is : " << tmp.get() << endl;
    cout << "mythread_other() ended and the thread id is " << std::this_thread::get_id() << endl;
}
int main(){
    cout << "main started and the thread id is " << std::this_thread::get_id() << endl;
    std::promise<int> myprom;
    std::thread t1(mythread, std::ref(myprom), 10);
    t1.join();
    std::future<int> res = myprom.get_future(); // future和promise绑定在一起。
    std::thread t2(mythread_other, std::ref(res));
    t2.join();
    return 0;
}

  输出结果为:

main started and the thread id is 0x1000e7d40
mythread() started and the thread id is 0x16fe87000
mythread() ended and the thread id is 0x16fe87000
mythread_other() started and the thread id is 0x16fe87000
mythread_other tmp.get() is : 11
mythread_other() ended and the thread id is 0x16fe87000
Program ended with exit code: 0

std::future

  卡住当前流程,等待std::async()的异步任务运行一段时间,然后返回其状态std::future_status。如果std::async()的参数std::launch::deferred(延迟执行),则不会卡住主流程。std::future_status是枚举类型,表示异步任务的执行状态。类型的取值有:std::future_status::timeoutstd::future_status::readystd::future_status::deferred

#include <iostream>
#include <future>
using namespace std;
int mythread() {
  cout << "mythread() started and the thread id is " << std::this_thread::get_id() << endl;
  std::chrono::milliseconds dura(5000); // 休息五秒
  std::this_thread::sleep_for(dura);
  cout << "mythread() ended and the thread id is " << std::this_thread::get_id() << endl;
  return 5;
}
int main() {
  cout << "main started and the thread id is " << std::this_thread::get_id() << endl;
  std::future<int> res = std::async(mythread); // 创建一个线程并开始执行
  cout << "continue ....." << endl;
  // std::future_status为枚举类型
  std::future_status status = res.wait_for(std::chrono::seconds(1)); // 等待1s钟
  if (status == std::future_status::timeout) { // 超时,表示线程还没有执行完,主线程等待1s钟,但是线程还没有执行完。
    cout << "超时,线程还没有执行完。" << endl;
  }
  else if (status == std::future_status::ready) {
    cout << "超时,线程成功执行完毕。" << endl;
    cout << res.get() << endl;
  }
  else if (status == std::future_status::deferred) {
    // std::future<int> res = std::async(std::launch::deferred, mythread); // 创建一个线程并延迟到get时执行
    cout << "超时,线程被延迟执行。" << endl;
    cout << res.get() << endl;
  }
  cout << "main ended and the thread id is " << std::this_thread::get_id() << endl;
}

  输出结果为:

std::shared_future

  get()只能使用一次,因为get()函数的设计是一个移动语义,相当于将result中的值移动到了复制对象中,再次get就报告了异常。如果有多个线程想要获得别的线程处理完的结果的话,shared_future就排上用场了。std::futureget()成员函数是转移数据。std::shared_futureget()成员函数是复制数据。

#include <thread>
#include <iostream>
#include <future>
using namespace std;
int mythread() {
  cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
  std::chrono::milliseconds dura(5000);
  std::this_thread::sleep_for(dura);
  cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
  return 5;
}
int main() {
  cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
  std::packaged_task<int()> mypt(mythread);
  std::thread t1(std::ref(mypt));
  std::future<int> result = mypt.get_future();
  bool ifcanget = result.valid(); //判断future 中的值是不是一个有效值
  std::shared_future<int> result_s(result.share()); //执行完毕后result_s里有值,而result里空了
  //std::shared_future<int> result_s(std::move(result));
   //通过get_future返回值直接构造一个shared_future对象
   //std::shared_future<int> result_s(mypt.get_future());
   t1.join();
  auto myresult1 = result_s.get();
  auto myresult2 = result_s.get();
  cout << "good luck" << endl;
  return 0;
}

  或者通过通过get_future返回值直接构造一个shared_future对象:

#include <thread>
#include <iostream>
#include <future>
using namespace std;
int mythread() {
  cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
  std::chrono::milliseconds dura(5000);
  std::this_thread::sleep_for(dura);
  cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
  return 5;
}
int main() {
  cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
  std::packaged_task<int()> mypt(mythread);
  std::thread t1(std::ref(mypt));
  t1.join();
  //std::future<int> result = mypt.get_future();
  //bool ifcanget = result.valid(); //判断future 中的值是不是一个有效值
  //std::shared_future<int> result_s(result.share()); //执行完毕后result_s里有值,而result里空了
  //std::shared_future<int> result_s(std::move(result));
   //通过get_future返回值直接构造一个shared_future对象
   std::shared_future<int> result_s(mypt.get_future());
  auto myresult1 = result_s.get();
  auto myresult2 = result_s.get();
  cout << "good luck" << endl;
  return 0;
}


相关文章
|
6天前
|
缓存 Java 调度
Java并发编程:深入解析线程池与Future任务
【7月更文挑战第9天】线程池和Future任务是Java并发编程中非常重要的概念。线程池通过重用线程减少了线程创建和销毁的开销,提高了资源利用率。而Future接口则提供了检查异步任务状态和获取任务结果的能力,使得异步编程更加灵活和强大。掌握这些概念,将有助于我们编写出更高效、更可靠的并发程序。
|
18天前
|
存储 前端开发 安全
C++一分钟之-未来与承诺:std::future与std::promise
【6月更文挑战第27天】`std::future`和`std::promise`是C++异步编程的关键工具,用于处理未完成任务的结果。`future`代表异步任务的结果容器,可阻塞等待或检查结果是否就绪;`promise`用于设置`future`的值,允许多线程间通信。常见问题包括异常安全、多重获取、线程同步和未检查状态。解决办法涉及智能指针管理、明确获取时机、确保线程安全以及检查未来状态。示例展示了使用`std::async`和`future`执行异步任务并获取结果。
28 2
|
19天前
|
存储 设计模式 安全
C++一分钟之-并发编程基础:线程与std::thread
【6月更文挑战第26天】C++11的`std::thread`简化了多线程编程,允许并发执行任务以提升效率。文中介绍了创建线程的基本方法,包括使用函数和lambda表达式,并强调了数据竞争、线程生命周期管理及异常安全等关键问题。通过示例展示了如何用互斥锁避免数据竞争,还提及了线程属性定制、线程局部存储和同步工具。理解并发编程的挑战与解决方案是提升程序性能的关键。
37 3
|
18天前
|
安全 程序员 C++
C++一分钟之-原子操作与线程安全
【6月更文挑战第27天】**C++的`std::atomic`提供线程安全的原子操作,解决多线程数据竞争。涵盖原子操作概念、应用、问题与对策。例如,用于计数器、标志位,但选择数据类型、内存顺序及操作组合需谨慎。正确使用能避免锁,提升并发性能。代码示例展示自旋锁和线程安全计数。了解并恰当运用原子操作至关重要。**
26 1
|
21天前
|
API C++
c++进阶篇——初窥多线程(三)cpp中的线程类
C++11引入了`std::thread`,提供对并发编程的支持,简化多线程创建并增强可移植性。`std::thread`的构造函数包括默认构造、移动构造及模板构造(支持函数、lambda和对象)。`thread::get_id()`获取线程ID,`join()`确保线程执行完成,`detach()`使线程独立,`joinable()`检查线程状态,`operator=`仅支持移动赋值。`thread::hardware_concurrency()`返回CPU核心数,可用于高效线程分配。
|
21天前
|
安全 API C++
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
14 0
|
5天前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
18 1
|
5天前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
15 1
|
3天前
|
缓存 Linux 编译器
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
11 0
|
3天前
|
存储 Linux 调度
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
14 0