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,一经查实,立即删除!

相关文章

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

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

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

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

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

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

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

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

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

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

防御性编程技巧

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

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

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

C++ 基本的输入输出

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

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…

flex 解析json文件_使用 Python 处理 JSON 格式的数据 | Linux 中国

如果你不希望从头开始创造一种数据格式来存放数据&#xff0c;JSON 是一个很好的选择。如果你对 Python 有所了解&#xff0c;就更加事半功倍了。下面就来介绍一下如何使用 Python 处理 JSON 数据。-- Seth KenlonJSON 的全称是 JavaScript 对象表示法JavaScript Object Notati…

【C语言】指针进阶第一站:字符指针 typedef关键字!

点击蓝字关注我们简单回顾一下指针的概念内存会划分以字节为单位的空间&#xff0c;每一个字节都有一个编号&#xff08;地址/指针&#xff09;指针变量可以存放这个地址/指针注&#xff1a;我们日常所说的指针&#xff0c;一般是指针变量下面让我们坐上指针进阶的直通车&#…

python编译helloworld_python3学习笔记--001--python HelloWorld

python默认使用UTF-8编码 一个python3版本的HelloWorld代码如下&#xff1a; #!/usr/bin/env python print (Hello World!) 如果此python脚本文件名为&#xff1a;hello.py&#xff0c;则运行此脚本文件的方法有两种&#xff1a; 1、python hello.py [laolanglocalhost python]…

漫谈 C++:良好的编程习惯与编程要点

点击蓝字关注我们以良好的方式编写C class假设现在我们要实现一个复数类complex&#xff0c;在类的实现过程中探索良好的编程习惯。① Header(头文件)中的防卫式声明complex.h: # ifndef __COMPLEX__ # define __COMPLEX__ class complex {} # endif防止头文件的内容被多次包含…

【C语言】指针进阶第二站:指针数组!

点击蓝字关注我们指针数组数组是一种类型的数的集合整型数组的元素都是int类型指针数组的元素都是指针变量int* arr1[10];//整型指针的数组char*arr2[10];//一级字符指针的数组char** arr3[5];//二级字符指针的数组参考这一份示意图示例1:定义多个字符指针在上一站的字符指针里…

C语言初学者常见错误 | 总结22点

点击蓝字关注我们正文一.语言使用错误在打代码的过程中&#xff0c;经常需要在中文与英文中进行转换&#xff0c;因此常出现一些符号一不小心就用错&#xff0c;用成中文。例如&#xff1a;“&#xff1b;”中文中的分号占用了两个字节&#xff0c;而英文中“;”分号只占用一个…

nginx配置vue项目500_一个Nginx部署多个vue前端项目总结

摘要&#xff1a;近来接手了一个二次开发的前后端分离模式的项目&#xff0c;其中在前端项目的部署上需要让2个前端项目都部署到一个IP地址和端口下&#xff0c;那么我们这里就要用到Nginx了&#xff0c;接下来我们看看如何在一个Nginx下部署2个前端项目的编译打包2个前端项目执…

【C语言】指针进阶第三站,数组指针!

点击蓝字关注我们数组指针整型指针&#xff1a;指向整型的指针字符指针&#xff1a;指向字符的指针数组指针&#xff1a;指向数组的指针基本概念下面哪个是数组指针呢&#xff1f;指针数组和数组指针的概念很容易混淆&#xff0c;一定要分清楚哦&#xff01;int *p1[10]; int (…

【C语言】指针进阶第四站:数组/指针的传参问题!

点击蓝字关注我们朋友们&#xff0c;到站啦&#xff01;指针进阶第四站&#xff1a;传参问题0.引例自定义函数里形参的类型&#xff0c;要和函数调用中传过去的实参类型相对应test函数里的是int类型&#xff0c;我们传过去的参数a也是int类型void test(int n) {} int main() {i…

python做自动化控制postman_python自动化测试入门篇-postman

接口测试基础-postman 常用的接口有两种&#xff1a;webservice接口和http api接口。 Webservice接口是走soap协议通过http传输&#xff0c;请求报文和返回报文都是xml格式。 http api接口是走http协议&#xff0c;通过路径来区分调用的方法&#xff0c;请求报文都是key-value形…