一、thread 类的简单介绍
在C++11之前,涉及到多线程问题,都是和平台相关的,比如 windows 和 linux 下各自有自己的接口,这使得代码的可移植性比较差,C++11中最重要的特性就是对线程进行支持,使得C++在并行编程时不需要依赖第三方库,而且在原子操作中还引入了原子类的概念。要使用标准库中的线程,必须包含 <thread> 头文件。
函数名 | 功能 |
thread() | 构造一个线程对象,没有关联任何线程函数,即没有启动任何线程 |
thread(fn, args1, args2...) | 构造一个线程对象,并关联线程函数fn,args1,args2,...为线程函数的参数 |
get_id() | 获取线程id |
joinable() | 线程是否还在执行,joinable代表的是一个正在执行中的线程 |
join() | 该函数调用后会阻塞住线程,当该线程结束后,主线程继续执行 |
detach() | 在创建线程对象后马上调用,用于把被创建的线程与线程对象分离开,分离的线程变为后台线程,创建的线程的“死活”就与主线程无关了 |
注意:
- 线程是操作系统中的一个概念,线程对象可以关联一个线程,用来控制线程以及获取线程的状态。
- 当创建一个线程对象后,没有提供线程函数,该对象实际上没有对应任何线程。get_id() 的返回值类型为 id 类型,id 类型实际上为 std::thread 命令空间下封装的一个类,该类中包含一个结构体:
#include <thread>
int main()
{
std::thread t1;
cout << t1.get_id() << endl;
return 0;
}
// vs下查看
typedef struct
{ /* thread identifier for Win32 */
void* _Hnd; /* Win32 HANDLE */
unsigned int _Id;
} _Thrd_imp_t;
- 当创建一个线程对象后,并且给线程关联线程函数,该线程就被启动,与主线程一起运行。现成函数一般情况下可以按照以下三种方式提供:
- 函数指针
- lambda 表达式
- 函数对象
#include <iostream>
using namespace std;
#include <thread>
void ThreadFunc(int a)
{
cout << "Thread1" << a << endl;
}
class TF
{
public:
void operator()()
{
cout << "Thread3" << endl;
}
};
int main()
{
// 线程函数为函数指针
thread t1(ThreadFunc, 10);
// 线程函数为lambda表达式
thread t2([] {cout << "Thread2" << endl; });
// 线程函数为函数对象
TF tf;
thread t3(tf);
t1.join();
t2.join();
t3.join();
cout << "Main thread!" << endl;
return 0;
}
- thread 类是防拷贝的,不允许拷贝构造以及赋值,但是可以移动构造和移动赋值,即将一个线程对象关联线程的状态转移给其他线程对象,转移期间不宜向线程的执行。
- 可以通过 joinable() 函数判断线程是否有效的,如果是以下任何一种情况,则线程无效:
- 采用无参构造函数构造的线程对象
- 线程对象的状态已经转移给其他线程对象
- 线程已经调用 join 或者 detach 结束
面试题:并发和并行的区别?
1. 并发(Concurrency)
- 定义:并发是指在同一时间段内,多个任务能够交替执行,虽然这些任务可能并不是同时进行,但它们的执行可以有重叠部分。简单来说,就是系统能够管理多个任务,并且能处理多个任务的执行。
- 特点:
- 并发关注的是任务的管理与调度。
- 在单核处理器中,通过时间片轮转等方式实现多个任务的交替执行。
- 任务间是“交替”进行的,但并不一定在同一时刻执行。
- 并发的核心是“交替”执行。
2. 并行(Parallelism)
- 定义:并行是指多个任务在同一时刻被同时执行。通常是在多核处理器或多台机器上,每个核心或机器处理一个任务,多个任务同时进行。
- 特点:
- 并行关注的是任务的同时执行。
- 并行通常需要多个处理器(或核心),这些处理器可以同时执行不同的任务。
- 在并行处理中,多个任务会真正“同时”进行。
总结区别:
- 并发强调的是系统可以在同一时间段内处理多个任务,但并不