[原]C++新标准之std::thread
概览
从C++11开始提供了线程的支持,终于可以方便的编写跨平台的线程代码了。除了std::thread类,还提供了许多其它便利同步的机制,本篇总结是C++11学习笔记系列的首篇总结。
std::thread
std::thread定义在<thread>中,提供了方便的创建线程的功能。
类定义
- class thread
- {
- public:
- thread() noexcept;
- thread( thread&& other ) noexcept;
- template< class Function, class... Args >
- explicit thread( Function&& f, Args&&... args );
- thread(const thread&) = delete;
- ~thread();
- thread& operator=( thread&& other ) noexcept;
- bool joinable() const noexcept;
- std::thread::id get_id() const noexcept;
- native_handle_type native_handle();
- void join();
- void detach();
- void swap( thread& other ) noexcept;
- static unsigned int hardware_concurrency() noexcept;
- };
从定义中我们可以得知:
- std::thread不支持拷贝语义。
- std::thread支持移动语义。
各个成员函数的简单介绍
- join() 可以用来等待线程结束,只能调用一次。
- joinable()是否与某个有效的线程关联。
- detach() 与当前线程分离。
- swap() 与另外一个std::thread交换。
- get_id()获取id。
- native_handle() 返回平台相关的数据,windows下是HANDLE。
- hardware_concurrency() 返回可并行运行的线程数量,只能作为一个参考。
例子
因为thread类比较简单,我们通过几个例子来学习。
- 支持移动语义,但不支持拷贝语义
- #include <thread>
- void some_function() {}
- void some_other_function() {}
- int main()
- {
- std::thread t1(some_function); // 构造一个thread对象t1
- std::thread t2 = std::move(t1); // 把t1 move给另外一个thread对象t2,t1不再管理之前的线程了。
- // 这句不需要std::move(),从临时变量进行移动是自动和隐式的。调用的是operator=(std::thread&&)
- t1 = std::thread(some_other_function);
- std::thread t3;
- t3 = std::move(t2); // 把t2 move给t3
- // 把t3 move给t1,非法。因为`t1`已经有了一个相关的线程,会调用`std::terminate()`来终止程序。
- t1 = std::move(t3);
- }
- 通过调用join()成员函数来等待线程结束
- #include <iostream>
- #include <thread>
- #include <chrono>
- void foo()
- {
- std::this_thread::sleep_for(std::chrono::seconds(1));
- }
- int main()
- {
- std::cout << "starting first helper...\n";
- std::thread helper1(foo);
- helper1.join();
- }
- 传递参数给线程函数
- void f(int i, std::string const& s);
- std::thread t(f, 3 "hello");
注意:参数会以默认的方式被复制到内部存储空间,直到使用的时候才会转成对应的类型。
下面的例子有问题吗?有什么问题?
- void f(int i, std::string const& s);
- void oops(int some_param)
- {
- char buffer[1024];
- sprintf(buffer, "%i", some_param);
- std::thread t(f, 3, buffer);
- t.detach();
- }
局部变量buffer的指针会被传递给新线程,如果oops()在buffer被转换成string之前退出,那么会导致未定义的行为。解决之道是在构造std::thread的时候传递string变量。std::thread t(f, 3, std::string(buffer));
可以使用std::ref()来显示表明要传递引用,就像std::bind()那样。
- std::thread t(update_data_for_widget, w, std::ref(data));
- 使用类的成员函数作为线程参数
- #include <thread>
- #include <string>
- class CRunner
- {
- public:
- void run0(){}
- void run1(int a) {}
- void run2(int a, int b) const {}
- int run3(int a, char b, const std::string& c) {return 0;}
- int run4(int& a, double b, float c, char d) { ++a; return 0; }
- static void run_static(int a) {}
- };
- int main()
- {
- CRunner runner;
- int a = 0;
- // 使用std::mem_fun,需要传指针
- std::thread t0(std::mem_fun(&CRunner::run0), &runner);
- // 使用std::mem_fun_ref,可以传引用或副本
- std::thread t1(std::mem_fun_ref(&CRunner::run1), std::ref(runner), 1);
- // std::thread t1(std::mem_fun_ref(&CRunner::run1), runner, 1);
- // 使用std::mem_fn,std::mem_fn支持多于一个参数的函数,std::mem_fun不支持。
- std::thread t2(std::mem_fn(&CRunner::run2), std::ref(runner), 1, 2);
- // 使用std::bind + std::mem_fn
- std::thread t3(std::bind(std::mem_fn(&CRunner::run3), &runner, 1, 2, "data"));
- // 使用std::mem_fn,注意std::ref的用法,如果不用std::ref行不行?
- std::thread t4(std::mem_fn(&CRunner::run4), &runner, std::ref(a), 2.2, 3.3f, 'd');
- // 使用类的静态函数
- std::thread t5(&CRunner::run_static, 1);
- t0.join();
- t1.join();
- t2.join();
- t3.join();
- t4.join();
- t5.join();
- }
注:
- std::mem_fun需要与类指针配合,std::mem_fun_ref可以和类引用或类副本配合。
- std::mem_fun或std::mem_fun_ref只支持最多一个参数的可调用对象(函数,仿函数等),在新标准中已经废弃不用了。
- std::mem_fn是std::mem_fun的增强版,不需要区分传递指针或者传递引用。而且可以支持传递多个参数。
- std::thread只需要一个可以调用的对象(函数,仿函数等),所以我们也可以通过std::bind()的返回值来作为std::thread的参数。
更多
虽然在之前的例子中的函数有返回值,但是我们却不能获得,想获得返回值我们需要使用std::future,关于std::future的总结,后续会慢慢补充,敬请期待。
参考资料
- 《C++并发编程实战》
- cppreference
[原]C++新标准之std::thread的更多相关文章
- [原]C++新标准之std::chrono::duration
原 总结 C++11 chrono duration ratio 概览 std::chrono::duration 描述 类定义 duration_cast()分析 预定义的duration 示例代 ...
- [原]C++新标准之std::chrono::time_point
原 总结 STL 标准库 chrono time_point ratio 概览 类定义 总结 思考 拓展 system_clock steady_clock high_resolution_cloc ...
- [原]C++新标准之std::ratio
原 总结 ratio 概览 类定义 预定义ratio 应用 示例代码 参考资料 概览 std::ratio定义在<ratio>文件中,提供了编译期的比例计算功能.为std::chrono ...
- mingw-w64线程模型:posix vs win32(posix允许使用c++11的std:: thread,但要带一个winpthreads,可能需要额外dll)
我正在安装 mingw-w64 on Windows,有两个选项: win32线程和posix线程. 我知道win32线程和pthreads之间的区别,但是我不明白这两个选项之间的区别. 我怀疑如果我 ...
- C++ std::thread概念介绍
C++ 11新标准中,正式的为该语言引入了多线程概念.新标准提供了一个线程库thread,通过创建一个thread对象来管理C++程序中的多线程. 本文简单聊一下C++多线程相关的一些概念及threa ...
- 第25课 std::thread对象的析构
一. 线程的等待与分离 (一)join和detach函数 1. 线程等待:join() (1)等待子线程结束,调用线程处于阻塞模式. (2)join()执行完成之后,底层线程id被设置为0,即join ...
- C++11 并发指南------std::thread 详解
参考: https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/blob/master/zh/chapter3-Thread/Int ...
- std::thread使用
本文将从以下三个部分介绍C++11标准中的thread类,本文主要内容为: 启动新线程 等待线程与分离线程 线程唯一标识符 1.启动线程 线程再std::threada对象创建时启动.最简单的情况下, ...
- C++11并发——多线程std::thread (一)
https://www.cnblogs.com/haippy/p/3284540.html 与 C++11 多线程相关的头文件 C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是< ...
随机推荐
- Day2-T3
原题目 Describe:质数问题 code: #pragma GCC optimize(2) #include<bits/stdc++.h> #define KKK 1200 using ...
- Pycharm2020最新激活码|永久激活(附最新激活码和插件)
最近很多人的Pycharm激活时间又过期了,后台很多人索要激活码,我就再把激活的方法汇和工具再梳理一次给大家. 最主要有两种激活方式(两种方式需要的激活码不同): 一.激活码激活: 一般一年多需要激活 ...
- Day 12:枚举值、枚举类
jdk1.5新特性之-----枚举 问题:某些方法所接收的数据必须是在固定范围之内的, 解决方案: 这时候我们的解决方案就是自定义一个类,然后是私有化构造函数,在自定义类中创建本类的对象对外使用. ...
- 高级数据类型(arrary、slice、map、ptr)
高级数据类型: 高级数据类型有数组.切片.map.指针.结构体.函数.接口.通道等,本文只介绍Arrary.Slice.map.ptr. 数组: (1)概念: 数组是同一种数据类型的集合.数组从声明时 ...
- ODBC OLEDB
ODBC OLEDB https://www.cnblogs.com/dachuang/p/8615754.html
- choice接口、同花顺使用
一 choice接口使用 1.choice软件-->量化-->下载中心,下载python接口文件 EMQuantAPI_Python 2.要先绑定手机号,绑定后账户权限不够,暂时放弃. 二 ...
- Causal Corpus 事件因果关系语料统计
Causal Corpus 事件因果关系语料统计 本文是对因果关系抽取领域数据库标注及开源情况的统计.除了对因果关系的标注,一些类似的语料也包含在内,从而为语料的使用提供灵活性,可以根据不同的目标选取 ...
- SQL基础教程(第2版)第3章 聚合与排序:3-4 对查询结果进行排序
第3章 聚合与排序:3-4 对查询结果进行排序 ● 使用ORDER BY子句对查询结果进行排序.● 在ORDER BY子句中列名的后面使用关键字ASC可以(通常省略默认)进行升序排序,使用DESC关键 ...
- 3. 现代 javascript 数组专题 和 对象专题
数组专题 展开运算符 使用...符号, 可以将数组"展开". 数组展开的妙用 ... eg: // 代替apply const foo = [1, 2, 3] const bar ...
- Python笔记_第一篇_面向过程_第一部分_5.Python数据类型之字符串类型(string)
关于Python的字符串处理也如其他语言一样属于重点中的重点,主要是牵扯到的函数和内容较为多和乱一些.关于什么是字符串,Python中的定义是:以单引号或者双引号括起来的任意文本. 1. 字符串的 ...