当前位置:   article > 正文

C++std::thread_c++ std::thread

c++ std::thread

本文章向大家介绍C++std::thread调用带参数和返回值的函数,主要包括C++std::thread调用带参数和返回值的函数使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

二、线程调用特殊函数

2.1 线程调用的函数含有参数

std::move,std::ref,引用

多线程中的函数参数如果为引用必须使用std::ref(函数式编程的参数默认使用拷贝方式),多线程中的函数参数如果为IO(socket应该也需要,没有测试过)必须使用移动语义(std::move),避免多个对象同时读写同一个IO缓冲

  1. #include <thread>
  2. #include <iostream>
  3. void fun(int& num) //参数为int&
  4. {
  5. while (num < 10)
  6. std::cout << num++;
  7. }
  8. int main()
  9. {
  10. int num = 0;
  11. std::thread t1(fun, std::ref(num));
  12. std::thread t2(fun, std::ref(num));
  13. t1.join();
  14. t2.join();
  15. return 0;
  16. }

2.2 线程调用成员函数

  1. #include <iostream>
  2. #include <thread>
  3. class A
  4. {
  5. public:
  6. void display(int a) { std::cout << a << '\n'; }
  7. };
  8. int main()
  9. {
  10. A a;
  11. std::thread t(&A::display, a, 3); //第一个参数必须带&,第二个可带可不带,第二个参数之后是调用函数的实参
  12. t.join();
  13. }

三、多线程执行含有返回值的函数,获取函数返回值

转载:C++ 中 async、packaged_task、promise 区别及使用

  • 将函数的返回值设置为输出参数

  • 使用std::future、std::promise和packaged_task

  • 使用lambda表达式获取函数返回值(如果线程执行太慢,主线程执行cout的时候result没有计算出来会出问题)。

lambda表达式

  1. #include <iostream>
  2. #include <thread>
  3. int f(int a, int b)
  4. {
  5. return a + b;
  6. }
  7. int main()
  8. {
  9. int result = 0;
  10. std::thread* t;
  11. t = new std::thread([&] { result = f(2, 3); });
  12. t->join();
  13. std::cout << result; //result = 5
  14. return 0;
  15. }

std::async和std::future的使用

转载:C++STL 线程:Future, Promise and async()

std::async()与std::thread()最明显的不同就是async只是创建异步任务,不一定创建线程。async()默认创建线程,可以设置第一个参数来决定是否创建线程。

  • async函数原型:
  1. std::async(std::launch::deferred,func,...) //不创建线程,直到调用get()在主线程执行调用的入口函数
  2. std::async(std::launch::async,func,...) //会创建线程,且立即执行
  3. std::async(std::launch::async | std::launch::deferred,func,...) //和std::launch::async一样,创建线程
  4. std::async(func,...) //和std::launch::async一样,创建线程
  • 获取函数返回值示例代码:
  1. //async的使用,配合future直接获取多线程中所调用函数的返回值
  2. #include <iostream>
  3. #include <thread>
  4. #include <future>
  5. int f(int a, int b)
  6. {
  7. using namespace std::chrono_literals;
  8. std::this_thread::sleep_for(5s); //睡眠五秒
  9. return a + b;
  10. }
  11. int main()
  12. {
  13. std::future<int> retVal = std::async(f, 2, 4);
  14. std::cout << "start" << '\n';
  15. std::cout << retVal.get(); //会阻塞,即主线程需要子线程执行完从而得到返回值
  16. std::cout << "end" << '\n';
  17. return 0;
  18. }
  19. //async,future析构阻塞问题
  20. #include <iostream>
  21. #include <thread>
  22. #include <future>
  23. int main()
  24. {
  25. auto sleep = [](int s) { std::this_thread::sleep_for(std::chrono::seconds(s)); };
  26. clock_t start = clock();
  27. {
  28. std::async(std::launch::async, sleep, 5); // 临时对象被析构,阻塞 5s
  29. std::async(std::launch::async, sleep, 5); // 临时对象被析构,阻塞 5s
  30. //auto f1 = std::async( std::launch::async, sleep, 5 );
  31. //auto f2 = std::async( std::launch::async, sleep, 5 );
  32. }
  33. std::cout << (clock() - start) / CLOCKS_PER_SEC << std::endl;
  34. return 0;
  35. }

std::promise和std::future的使用

转载C++之future和promise

promise作为参数应该以引用的形式传入(),因此需要使用std::ref()

future和promise的作用是在不同线程之间传递数据。使用指针也可以完成数据的传递,但是指针非常危险,因为互斥量不能阻止指针的访问;而且指针的方式传递的数据是固定的,如果更改数据类型,那么还需要更改有关的接口,比较麻烦;promise支持泛型的操作,更加方便编程处理。std::promise的作用就是提供一个不同线程之间的数据同步机制,它可以存储一个某种类型的值,并将其传递给对应的future, 即使这个future不在同一个线程中也可以安全的访问到这个值。
示例代码:

  1. //promise的使用,多线程中的函数所使用的参数需要其他线程返回
  2. //1.子线程使用主线程传入的值
  3. #include <thread>
  4. #include <future>
  5. #include <iostream>
  6. void task(/*std::future<int> i*/std::promise<int>& i)
  7. {
  8. std::this_thread::sleep_for(std::chrono::seconds(1));
  9. std::cout << i.get_future().get();
  10. //std::cout << i.get() ; // 阻塞,直到 p.set_value() 被调用
  11. }
  12. int main()
  13. {
  14. //lambda表达式和函数效果一样
  15. //auto task = [](std::future<int> i)
  16. //{
  17. // std::this_thread::sleep_for(std::chrono::seconds(3));
  18. // std::cout << i.get() << std::flush; // 阻塞,直到 p.set_value() 被调用
  19. //};
  20. std::promise<int> p;
  21. //std::thread t(task, p.get_future());
  22. std::thread t(task, std::ref(p));
  23. p.set_value(5);
  24. t.join(); //调用完join后执行task(),因此在这里会阻塞
  25. return 0;
  26. }
  27. //2.主线程使用子线程得到的值
  28. //#include <iostream>
  29. //#include <future>
  30. //#include <thread>
  31. //
  32. //void task(std::promise<int>& i)
  33. //{
  34. // //dosomething
  35. // int value = 8;
  36. // i.set_value(value);
  37. //}
  38. //
  39. //int main()
  40. //{
  41. // std::promise<int> pro;
  42. // std::future<int> ret = pro.get_future();
  43. //
  44. // std::thread t(task, std::ref(pro));
  45. // t.join();
  46. //
  47. // std::cout << "get value:" << ret.get() << std::endl;
  48. //
  49. // system("pause");
  50. // return 0;
  51. //}

std::packaged_task和std::future的使用

std::packaged_task的作用就是提供一个不同线程之间的数据同步机制,std::packaged_task本身和线程没有关系,它只是关联了一个std::future的仿函数。需要显式的调用或者传递给std::thread进行异步调用,所以它更灵活(可以选择什么时候开始任务)。

std::packaged_task 对象内部包含了两个最基本元素

  • 被包装的任务(stored task),任务(task)是一个可调用的对象,如函数指针、成员函数指针或者函数对象

  • 共享状态(shared state),用于保存任务的返回值,可以通过 std::future 对象来达到异步访问共享状态的效果。
    示例代码

  1. //packaged_task的使用,直接得到多线程调用函数的返回值
  2. #include <iostream> // std::cout
  3. #include <utility> // std::move
  4. #include <future> // std::packaged_task, std::future
  5. #include <thread> // std::thread
  6. int fun(int a)
  7. {
  8. std::this_thread::sleep_for(std::chrono::seconds(3));
  9. return 2 * a;
  10. }
  11. int main()
  12. {
  13. std::packaged_task<int(int)> foo(fun);
  14. std::future<int> ret = foo.get_future();
  15. std::thread t(std::move(foo), 19);
  16. t.join(); //阻塞,调用fun函数得到返回值
  17. std::cout << ret.get();
  18. return 0;
  19. }

async、promise、paceaged_task三者的区别与联系

  • 用 std::async 来做简单的事情,例如异步执行一个任务。但是要注意 std::future 析构阻塞的问题。

  • std::packaged_task 能够很轻松的拿到 std::future,选择是否配合 std::thread 进行异步处理。同时没有析构阻塞的问题。

  • std::promise 是三者中最底层的能力,可以用来同步不同线程之间的消息

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/153527
推荐阅读
相关标签
  

闽ICP备14008679号