为什么要有线程库
我们在Linux中写多线程的时候使用的是Linux下提供的多线程的一套api
但是如果我们的运行环境变成了windows呢 windows提供的多线程api肯定和Linux不同
也就是说 我的代码可移植性很差 这个时候如果有一个语言层面的库就能解决移植性的问题了
而在C++11中最重要的特性就是对线程进行支持了 使得C++在并行编程时不需要依赖第三方库 而且在原子操作中还引入了原子类的概念 要使用标准库中的线程 必须包含thread头文件
线程库介绍
线程库常见的接口
成员函数 | 用处 |
thread() | 构造一个线程对象,没有关联任何线程函数,即没有启动任何线程 |
get_id() | 获取线程id |
jionable() | 线程是否还在执行,joinable代表的是一个正在执行中的线程。 |
jion() | 该函数调用后会阻塞住线程,当该线程结束后,主线程继续执行 |
detach() | 在创建线程对象后马上调用,用于把被创建线程与线程对象分离开,分离的线程变为后台线程,创建的线程的"死活"就与主线程无关 |
构造线程对象
方式一 : 无参构造
函数如下
thread();
这是一个无参构造 所以说创建出来之后并没有任何的任务与其相关联 如果我们需要使用移动构造赋予其一个任务
代码表示如下
void func(int n) { for (int i = 0; i < n; i++) { cout << i << endl; } } int main() { thread t1; t1 = thread(func, 10); t1.join(); return 0; }
方式二: 带参构造
函数如下
template <class Fn, class... Args> explicit thread (Fn&& fn, Args&&... args);
此时我们只需要省略无参构造t1的过程 直接使用构造函数即可 代码表示如下
void func(int n) { for (int i = 0; i < n; i++) { cout << i << endl; } } int main() { thread t1(func, 10); t1.join(); return 0; }
方式三 拷贝构造
在C++中的thread库中 我们禁止了拷贝构造 在这里特地强调下
方式四 移动构造
函数如下
thread (thread&& x) noexcept;
使用方式和第一种无参构造很类似 代码表示如下
void func(int n) { for (int i = 0; i < n; i++) { cout << i << endl; } } int main() { thread t1 = thread(func, 10); t1.join(); return 0; }
获取线程id
函数原型如下
this_thread::get_id()
我们可以使用该函数来获取线程的id 代码和运行结果如下
void func(int n) { cout << this_thread::get_id() << endl; } int main() { thread t1 = thread(func, 10); t1.join(); return 0; }
join和deteach
thread库中提供给我们这两个函数的用途主要是让我们去回收我们的线程资源
join
当我们调用 join()
函数的时候主线程会被阻塞
当新线程终止的时候主线程回去回收对应的资源 代码和运行结果如下
void func(int n) { cout << this_thread::get_id() << endl; } int main() { thread t1 = thread(func, 10); t1.join(); return 0; }
注意点:
- join的作用是回收资源 如果说我们连续对于一个地方回收两次资源则会造成程序崩溃
deteach
当我们调用 deteach()
函数的时候 就相当于主线程和新线程之间没有关系了
各跑各的
代码和示例如下
void func(int n) { cout << this_thread::get_id() << endl; } int main() { thread t1 = thread(func, 10); t1.join(); Sleep(1); return 0; }
注意点:
- 我们在主线程的代码中如果不加sleep(1) 那么有可能新线程还没跑起来 整个进程就运行结束