多线程简介

本节阅读量:

使用多线程技术,可以在一个进程中同时存在多条并行的执行流。这带来了如下两个好处:

  1. 提高系统并发能力。就比如在食堂,多个打菜的窗口,能同一时间打出的菜,比一个窗口,是有倍数的提升。
  2. 充分利用cpu资源,提高并行能力。现代cpu上,会有多个核心。对于cpu密集的任务,单个执行流就可以消耗完单核心的计算能力。使用多线程,可以充分利用硬件资源,并行处理,加速计算。

多线程的语法非常简单,但是想写出没有问题的多线程代码,却需要深入的思考。单线程的程序出问题了,使用调试工具逐步追踪,最终还是能够修正的。如果对多线程的程序设计没有了解和掌握,那么永远不可能写出正确的多线程代码。

当然,掌握一定套路之后,多线程还是一个较为简单,同时又非常强大的工具。


简单示例

让我们从一个简单的例子开始:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <thread>

void odd()
{
	for (int i = 0; i < 10; i += 2)
	{
		std::cout << i;
	}
}

void even()
{
	for (int i = 1; i < 10; i += 2)
	{
		std::cout << i;
	}
}

int main()
{
	std::cout << "Start Two Thread!\n";
	std::thread o(odd);   // 启动打印偶数的线程
	std::thread e(even);  // 启动打印奇数的线程
	o.join();  // 等待线程 o 执行结束,这里可以理解为 main.wait_finish(o)
	e.join();  // 等待线程 e 执行结束
	std::cout << "\nTwo Thread Work Done\n";
	return 0;
}

在作者的机器上,这打印如下的结果:

1
2
3
Start Two Thread!
0246813579
Two Thread Work Done

当然,这只是恰巧打印了这样的结果,有可能奇数和偶数会交错打印。因为线程o和线程e,两者之间是完全独立执行的,没有任何先后顺序。

这段代码有如下的行为:

  1. “std::thread o(odd);”,启动了一个独立的执行流,该执行流完全和main函数并行,并从odd函数体的第一行开始执行。然后开始打印0到8的偶数。然后执行到odd函数结尾停止。
  2. “std::thread e(even);”,同理,启动了一个打印1到9的奇数的执行流,该执行流也是与main函数并行。
  3. “o.join();”,在main函数中,等待线程o的执行完成,如果线程o一直未执行完成,则一直在这里等待。
  4. “e.join();”,在main函数中,等待线程e的执行完成。

至此,我们完成了在main函数中进行多个线程的启动,以及等待它们完成的程序。

看起来相当简单。

下一节,来详细了解下“std::thread”的各个方面。


常用库

上一节

0.1 线程的生命周期

下一节