[c++11]多线程编程(一)——初识

发布时间:2019-08-06 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了[c++11]多线程编程(一)——初识脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

什么是并发

并发在生活中随处可见,边走路边说话,边听歌边写代码。计算机语中的"并发",指的是在单个系统里同时执行多个独立的活动,而不是顺序的一个接一个的执行。对于单核CPU来说,在某个时刻只可能处理一个任务,但它却不是完全执行完一个任务再执行一个下一任务,而是一直在任务间切换,每个任务完成一点就去执行下一个任务,看起来就像任务在并行发生,虽然不是严格的同时执行多个任务,但是我们仍然称之为并发(concurrency)。真正的并发是在在多核CPU上,能够真正的同时执行多个任务,称为硬件并发(hardware concurrency)

并发并非没有代价,在单核CPU并发执行两个任务需要付出上下文切换的时间代价。如下图:

[c++11]多线程编程(一)——初识

假设A和B两个任务都被分成10个大小相等的块,单核CPU交替的执行两个任务,每次执行其中一块,其花费的时间并不是先完成A任务再玩成B任务所花费时间的两倍,而是要更多。这是因为系统从一个任务切换到另一个任务需要执行一次上下文切换,这是需要时间的(图中的灰色块)。上下文切换需要操作系统为当前运行的任务保存CPU的状态和指令指针,算出要切换到哪个任务,并为要切换的任务重新加载处理器状态。然后将新任务的指令和数据载入到缓存中。

并发的方式

多进程并发

将应用程序分为多个独立的、单线程的进程,他们可以同时运行。进程内部实现原理比较复杂,这里就不多说了。

[c++11]多线程编程(一)——初识

这些独立的进程可以通过常规的进程间通信机制进行通信,如管道、信号、消息队列、共享内存、存储映射I/O、信号量、套接字等。

缺点:

  • 进程间通信较为复杂,速度相对线程间的通信更慢。
  • 启动进程的开销比线程大,使用的系统资也更多。

优点:

  • 进程间通信的机制相对于线程更加安全。
  • 能够很容易的将一台机器上的多进程程序部署在不同的机器上(如果通信机制选取的是套接字的话)。

多线程并发

线程很像轻量级的进程,但是一个进程中的所有线程都共享相同的地址空间,线程间的大部分数据都可以共享。线程间的通信一般都通过共享内存来实现。

[c++11]多线程编程(一)——初识

优点:

  • 由于可以共享数据,多线程间的通信开销比进程小的多。
  • 线程启动的比进程快,占用的资源更少。

缺点:

  • 共享数据太过于灵活,为了维护正确的共享,代码写起来比较复杂。
  • 无法部署在分布式系统上。

为什么使用并发

主要原因有两个:任务拆分和提高性能。

任务拆分

在编写软件的时候,将相关的代码放在一起,将无关的代码分开,这是一个好主意,这样能够让程序更加容易理解和测试。将程序划分成不同的任务,每个线程执行一个任务或者多个任务,可以将整个程序的逻辑变得更加简单

提高性能

在两种情况下,并发能够提高性能。

  1. 任务并行(task parallelism):将一个单个任务分成若干个部分各自并行运行,从而降低运行时间。虽然听起来很简单,但其实是一个相当复杂的过程,设想假如各个部分之间存在很多以来,一个部分的执行需要使用到另一个任务的执行结果,这个时候并不能很好的并行完成。
  2. 数据并行(data parallelism):每个线程在不同的数据部分上执行相同的操作。

多线程库简介

C++98标准中并没有线程库的存在,而在C++11中终于提供了多线程的标准库,提供了管理线程、保护共享数据、线程间同步操作、原子操作等类。

多线程库对应的头文件#include <thread>,类名为std::thread

一个简单的串行程序如下: