std::thread 还有哪些使用“姿势”?

点击蓝字

7cf1259efd9a67b93fdc06798a74ba20.png

关注我们

C++11 线程创建

每一个 C++11 程序都包含一个主线程即 main() 函数。在 C++11 中我们可以通过创建 std::thread 对象来创建新的线程。

每个 std::thread 对象都可以与一个线程相关联。

需要引用的头文件:

1
#include <thread>

std::thread 的构造函数中接受什么参数?

我们可以给 std::thread 对象添加函数,这个回调函数将在这个新线程启动时执行。这些回调可以是:

1.) 函数指针
2.) 函数对象
3.) Lambda 函数

创建 thread 对象:

1
std::thread thObj(<CALLBACK>);

新线程将在创建新对象后立即启动,并将并行地执行(当参数)传递给线程的回调函数。

此外,任何线程都可以通过调用某线程对象上的 join( ) 函数来等待此线程退出。

让我们看一个例子,主线程将创建另外一个线程。创建这个新线程后,主线程会在控制台上打印一些数据,然后等待新创建的线程退出。

下面我们使用三种不同回调机制来实现上面的内容。

使用函数指针创建线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <thread>void thread_function()
{for(int i = 0; i < 10000; i++);std::cout<<"thread function Executing"<<std::endl;
}int main()  
{std::thread threadObj(thread_function);for(int i = 0; i < 10000; i++);std::cout<<"Display From MainThread"<<std::endl;threadObj.join();    std::cout<<"Exit of Main function"<<std::endl;return 0;
}

使用函数对象创建线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>
class DisplayThread
{
public:void operator()()     
{for(int i = 0; i < 10000; i++)std::cout<<"Display Thread Executing"<<std::endl;}
};int main()  
{std::thread threadObj( (DisplayThread()) );for(int i = 0; i < 10000; i++)std::cout<<"Display From Main Thread "<<std::endl;std::cout<<"Waiting For Thread to complete"<<std::endl;threadObj.join();std::cout<<"Exiting from Main Thread"<<std::endl;return 0;
}

使用 Lambda 函数创建线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <thread>
int main()  
{int x = 9;std::thread threadObj([]{for(int i = 0; i < 10000; i++)std::cout<<"Display Thread Executing"<<std::endl;});for(int i = 0; i < 10000; i++)std::cout<<"Display From Main Thread"<<std::endl;threadObj.join();std::cout<<"Exiting from Main Thread"<<std::endl;return 0;
}

如何区分线程

每个 std::thread 对象都有一个 ID,使用下面的函数可以获取:

1
std::thread::get_id()

获取当前线程的 ID:

1
std::this_thread::get_id()

如果 std::thread 对象没有和任何对象关联,则 get_id() 函数会返回默认构造的 std::thread::id 对象,即“非线程”。

std::thread::id 是一个对象,它也可以在控制台上进行比较和打印。让我们来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <thread>
void thread_function()
{std::cout<<"Inside Thread :: ID  = "<<std::this_thread::get_id()<<std::endl;    
}
int main()  
{std::thread threadObj1(thread_function);std::thread threadObj2(thread_function);if(threadObj1.get_id() != threadObj2.get_id())std::cout<<"Both Threads have different IDs"<<std::endl;std::cout<<"From Main Thread :: ID of Thread 1 = "<<threadObj1.get_id()<<std::endl;    std::cout<<"From Main Thread :: ID of Thread 2 = "<<threadObj2.get_id()<<std::endl;    threadObj1.join();    threadObj2.join();    return 0;
}


std::thread 的搭配用法


std::promise

为了在不同的线程之间传递数据,C++ 引入了 std::promise 和 std::future 这两种数据结构,在头文件 <future> 中包含。

promise 是一个范型的数据结构,你可以定义一个整形的 promise:promise<int>,这意味着线程之间传递的值是整形。

promise 的 get_future() 方法返回一个 future 数据结构,从这个 future 数据结构可以获取设置给 promise 的值,下面是一个例子:

#include <iostream>
#include <future>
#include <thread>using namespace std;int main() {promise<int> a_promise;  auto a_future = a_promise.get_future();  a_promise.set_value(10);  cout << a_future.get() << endl;cout << "after get()" << endl;return 0;
}

上面例子的输出结构是:

10
after get()

实际上,上面的例子并没有使用线程,但是很好得展示了 promise 和 future 之间的关系。

更复杂一点的使用场景可能是下面这样子的:

  • 主线程定义一个promise,命名为p

  • 主线程调用p.get_future(),并把返回值保存为引用f

  • 主线程启动一个子线程,并把p作为启动参数传给子线程

  • 主线程调用f.get(),但是此时子线程还未将数据放入promise内,所以主线程挂起

  • 子线程执行完,获取到结果,并把结果写入p

  • 主线程从f.get()的调用中被唤醒,获取到子线程写入p的值,继续执行

std::packaged_task

C++11很贴心地提供了packaged_task类型,让我们不用直接使用std::thread和std::promise,直接就能够生成线程,派遣任务:

#include <iostream>
#include <future>using namespace std;int f() {string hi = "hello, world!";cout << hi << endl;return hi.size();
}int main() {packaged_task<int ()> task(f);auto result = task.get_future();task();cout << result.get() << endl;return 0;
}

上面代码的运行结果为:

hello, world!
13

std::async

std::packaged_task 要求你自己启动任务,比如上一章节例子中你要显示调用 task()。如果连这一步都想省了的话,可以使用 std:async:

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future> template <typename RandomIt>int parallel_sum(RandomIt beg, RandomIt end)
{auto len = end - beg;if (len < 1000) return std::accumulate(beg, end, 0);RandomIt mid = beg + len/2;auto handle = std::async(std::launch::async,parallel_sum<RandomIt>, mid, end);int sum = parallel_sum(beg, mid);return sum + handle.get();
}int main()
{std::vector<int> v(10000, 1);std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';
}

上面的代码来自 cpp reference ,运行结果:The sum is 10000。

std::this_thread

C++11专门提供了一个命名空间std::this_thread来表示当前线程。std::this_thread提供了几个方法可以对线程做一定的控制:

  • get_id(),获取线程id

  • yield(), 释放执行权

  • sleep_for(),使线程沉睡一定时间

下面是一个具体例子:

#include <iostream>#include <future>#include <thread>using namespace std;int f(promise<int> my_promise) {string hi = "hello, world!";my_promise.set_value(hi.size());this_thread::sleep_for(0.1s);cout << hi << endl;
}int main() {promise<int> f_promise;auto result = f_promise.get_future();thread f_thread(f, move(f_promise));cout << result.get() << endl;f_thread.join();return 0;
}

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

88ba3b5a67d5be953adbe768cc7dcd0d.png

e467232e5c7ebd633b84869db8522e56.gif

戳“阅读原文”我们一起进步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337497.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python3反转字符串

Python3反转字符串原题 https://leetcode-cn.com/problems/reverse-string-ii/题目&#xff1a; 给定一个字符串和一个整数 k&#xff0c;你需要对从字符串开头算起的每个 2k 个字符的前k个字符进行反转。如果剩余少于 k 个字符&#xff0c;则将剩余的所有全部反转。如果有小于…

用python画皇冠_手把手教你用 Python 绘制酷炫的桑基图!

原标题&#xff1a;手把手教你用 Python 绘制酷炫的桑基图&#xff01;作者 | 周志鹏 责编 | 郭 芮 最近&#xff0c;不止一次收到小伙伴的截图追问&#xff1a;“这个图叫什么&#xff1f;&#xff1f;&#xff1f;” “这个图真好看&#xff01;&#xff01;&#xff01;怎么…

ejb能调用另一个ejb吗_异步EJB只是一个Gi头吗?

ejb能调用另一个ejb吗在之前的文章&#xff08; 此处和此处 &#xff09;中&#xff0c;我展示了当服务器负载沉重时&#xff0c;创建非阻塞异步应用程序可以提高性能。 EJB 3.1引入了Asynchronous批注&#xff0c;用于指定方法将在将来的某个时间返回其结果。 Javadocs声明必须…

为啥电脑从C盘开始?A、B盘去哪了?

点击蓝字关注我们前些天硬盘坏了&#xff0c;幸好不是系统盘&#xff0c;不然那些软件安装配置会把我折腾坏&#xff0c;或许这也是在暗示我该换电脑了。重要的数据部分没有遭到损坏&#xff0c;数据是无价的&#xff0c;还是要勤备份。于是换上了一张新的硬盘&#xff0c;当时…

Python3求最后一个单词长度

Python3求最后一个单词长度原题&#xff1a;https://leetcode-cn.com/problems/length-of-last-word/ 给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s&#xff0c;返回其最后一个单词的长度。如果字符串从左向右滚动显示&#xff0c;那么最后一个单词就是最后出现的单词。 …

java 锁_Java之线程并发的各种锁、锁、锁

因为两周没更新了...也不是懒&#xff0c;这两周确实有些忙&#xff0c;赶项目进度赶的不亦乐乎...终于赶在工期前&#xff0c;可以进入内测了&#xff0c;我也有了些时间&#xff0c;可以更新啦...线程并发锁是很常见的问题&#xff0c;而且在Java中锁的类型、概念、使用场景等…

threadsafe_Agrona的Threadsafe堆缓冲区

threadsafe这篇博客文章通过说明我们如何轻松访问线程内存来进行线程安全操作&#xff0c;继续了我在Agrona库上进行的系列文章 。 在继续讨论这是一个相当高级的主题之前&#xff0c;我可能应该警告一下&#xff0c;并且我不尝试解释诸如内存屏障之类的概念&#xff0c;仅概述…

C语言编程中错误异常该如何统一处理?1.8万字总结

点击蓝字关注我们本文主要总结嵌入式系统C语言编程中&#xff0c;主要的错误处理方式。一、错误概念1.1 错误分类从严重性而言&#xff0c;程序错误可分为致命性和非致命性两类。对于致命性错误&#xff0c;无法执行恢复动作&#xff0c;最多只能在用户屏幕上打印出错消息或将其…

Python3实现最小栈

Python3实现最小栈原题 https://leetcode-cn.com/problems/min-stack/ 设计一个支持 push&#xff0c;pop&#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 push(x) – 将元素 x 推入栈中。 pop() – 删除栈顶的元素。 top() – 获取栈顶元素。 getMin…

pycharm remote 远程项目 同步 本地_利器:PyCharm本地连接服务器搭建深度学习实验环境的三重境界...

作为实验室社畜&#xff0c;常需要在本地使用Pycharm写代码&#xff0c;然后将代码同步到服务器上&#xff0c;使用远程登录服务器并运行代码做实验。这其中有很多事情如果没有好的工具&#xff0c;做起来会非常麻烦。比如如何快速同步本地与服务器的代码&#xff1f;如何优雅地…

防御性编程技巧

点击蓝字关注我们在防御性编程的大框架之下&#xff0c;有许多常识性的规则。人们在想到防御性编程的时候&#xff0c;通常都会想到“断言”&#xff0c;这没有错。我们将在后面对此进行讨论。但是&#xff0c;还是有一些简单的编程习惯可以极大地提高代码的安全性。尽管看上去…

unity创建和销毁对象_如何创建和销毁对象

unity创建和销毁对象本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题&#xff0c;包括对象创建&#xff0c;并发&#xff0c;序列化&#xff0c;反射等。 它将指导您完成Java掌握的旅程&#xff01; 在这里查看 &…

Python3实现打家劫舍问题

Python3实现打家劫舍问题原题 https://leetcode-cn.com/problems/house-robber/ 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同…

cookie无法读取bdstoken_第二章(第12节):cookie操作

有时候我们需要验证浏览器中 cookie 是否正确&#xff0c;因为基于真实 cookie 的测试是无法通过白盒和集成测试进行的。WebDriver 提供了操作 cookie 的相关方法&#xff0c;可以读取、添加和删除 cookie信息。WebDriver 操作 cookie 的方法&#xff1a;get_cookies()&#xf…

js 序列化内置对象_内置序列化技术

js 序列化内置对象本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题&#xff0c;包括对象创建&#xff0c;并发&#xff0c;序列化&#xff0c;反射等。 它将指导您完成Java掌握的旅程&#xff01; 在这里查看 &#x…

C++ 基本的输入输出

点击蓝字关注我们C 标准库虽然提供了一组丰富的输入/输出功能&#xff0c;但是本章只讨论 C 编程中最基本和最常见的 I/O 操作。C 的 I/O 发生在流中&#xff0c;流是字节序列。如果字节流是从设备&#xff08;如键盘、磁盘驱动器、网络连接等&#xff09;流向内存&#xff0c;…

Python3有效括号问题

Python3有效括号问题原题 https://leetcode-cn.com/problems/valid-parentheses/ 给定一个只包括 ‘(’&#xff0c;’)’&#xff0c;’{’&#xff0c;’}’&#xff0c;’[’&#xff0c;’]’ 的字符串&#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左…

http 和 https_HTTPS与HTTP区别

HTTPS与HTTP的认识&#xff1a;HTTP 加密 认证 完整性保护 HTTPSHTTP的全称是 Hypertext Transfer Protocol Vertion (超文本传输协议)HTTPS&#xff1a; HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议。HTTPS和HTTP的区别&#xff1a;HTTPS协议需要到ca申…

C语言指针的自我介绍(你了解我吗?了解多少?)

点击蓝字关注我们hey! Ladies and Gentlemen.&#x1f601;欢迎大家来看望我&#xff0c;对&#xff0c;我就是指针(pointer)&#xff0c;被很多人吐槽&#x1f614;&#xff0c;也被人说好。我希望大家了解过我以后&#xff0c;能够爱上我&#x1f618;。大家在了解我之前 &am…

Python3最长连续递增序列问题

Python3最长连续递增序列问题原题 https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/ 题目&#xff1a; 给定一个未经排序的整数数组&#xff0c;找到最长且连续的的递增序列。 示例 1: 输入: [1,3,5,4,7] 输出: 3 解释: 最长连续递增序列是 [1…