本笔记从B站同名课程:C++11并发与多线程P2开始记录,如有不足,望广大读者不吝指出。
程序开发环境:C++11,windows VS2017
目录
0. 创建新项目
打开vs2017,左上角文件-新建-项目,选择控制台应用,自定义名称及存储位置后点击确定。
项目新建完成后页面如下
ctrl+F5可输出初始代码“Hello World”:
还有一些常用快捷键:F9增加/取消断点,F5运行程序到断点进而用F10逐过程调试等
1. 并发、进程、线程的基本概念及综述
1.1 并发
所谓并发,指的是两个或者更多的任务(独立的活动)同时发生(进行),对计算机而言就是一个程序同时执行多个独立的任务。
以往的计算机只具备单核的CPU,某一时刻只能执行一个任务。要想同时执行多任务,需要由操作系统调度,每秒钟进行多次所谓的“任务切换”(任务一先执行几毫秒,任务二再执行几毫秒...一个循环后执行回任务一,任务一从执行完几毫秒后的状态继续执行几毫秒...)。这种并不是真正的并发,是一种切换时间极短而造成的并发的假象。这种切换有时间开销,比如操作系统要保存切换前某任务的各种状态(变量信息),执行进度等,一会儿切换回这个任务时要复原这些信息,这些都需要时间。
随着硬件发展,出现了多处理器的计算机,用于服务器和高性能计算领域。现在的计算机在一个芯片上往往有多个CPU(双核,4核,8核,16核....)。能够实现真正地并行执行多任务(硬件并发)。
然而即便是已经具备多核处理器,线程数依然远多于核数。以下是我的电脑此时正存在的线程数2982。这说明我电脑的8个CPU还是在进行“任务切换”。
以下是多核多任务的处理方式:每个核都在进行任务切换,保证每个任务都会有一定的执行时间。至于每个核在某一时刻执行哪个任务,此调度算法由操作系统给出。这里不做拓展。
使用并发的原因:主要是在同时做多件事,提高计算性能。
1.2 可执行程序
磁盘上的一个文件,windows下拓展名为.exe,linux下具有x执行权限的文件都称作可执行文件。
1.3 进程
可执行程序运行起来了,就叫做创建了一个进程。
在原始程序中,我们加入一个死循环,根据任务管理器查看进程情况。
ctrl+f5运行程序,可见此进程并未退出(未显示进程xxx已退出字样)
在任务管理器-用户下,我们可以找到刚才创建的进程Multithreading.exe(因为是死循环,很占CPU)
然后在vs的程序界面再按ctrl+f5再开启一个同样名字的进程。在任务管理器就会存在两个相同名字的进程。Multithreading.exe
1.4 线程
每个进程都有一个主线程,且主线程唯一。当可执行文件执行后,进程创建,主线程就自动起来了。ctrl+f5运行程序的时候,实际上是进程的主线程来执行main函数中的代码。主线程与进程唇齿相依,有我就有你,没我就没你。
实际上线程就是执行代码的。线程就是代码的执行道路。
除了主线程之外, 我们可以通过自己写代码来创建其他线程。其他线程走的是别的道路,甚至去了不同的地方(执行不同的代码流程)。每创建一个新线程,就可以在同一时刻,多干几件不同的事。线程不是越多越好,每个线程都需要一个独立的堆栈空间(1M),线程之间的切换要保存很多的中间状态,会耗费本该属于程序运行的时间。
小结:进程与线程之间的区别和联系
1.线程是用来执行代码的
2.线程可以理解为一条执行代码的通路,一条新线程就是代表一条新的通路。
3.一个进程自动包括一个主线程,主线程随着进程默默启动并运行,我们可以通过编码来创建多个其他线程(非主线程)。但是创建的数量不建议超过200-300个。至于到底创建多少个合适,可以在实际项目中不断调整和优化,有时候线程太多的时候效率反而会降低。
4.因为主线程是自动启动的,所以一个进程中至少存在一个线程(主线程)。
5.多进程程序可以同时干很多事,所以运行效率高。但是到底有多高并不是很容易评估和量化。依然需要在实际项目中进行体验和调整优化。
2. 并发的实现方法
并发是使两个或更多的任务(独立的活动)同时发生,实现的手段有以下两种:
a)通过多个进程实现并发。
b)在单独的进程中创建多个线程,自己写代码来创建除了主线程之外的其他线程。
2.1 多进程并发
多进程并发要考虑到进程之间的通信。
如果进程在同一个电脑上,可以采用管道,文件,消息队列,共享内存等方式实现。
如果进程在不同电脑上,可以采用socket通信实现。
2.2 多线程并发
在单个进程中创建多个线程。
每个线程都有自己独立的运行路径,但是一个进程中所有线程共享地址空间(共享内存)。全局变量,指针,引用都可以在线程之间传递。使用多线程开销远小于多进程。共享内存带来新的问题:数据一致性问题。线程AB同时往一块内存写数据的时候要考虑先来后到,不然内存很可能被后来的线程覆盖。
小结:多进程并发与多线程并发的优劣对比
多进程并发和多线程并发虽然可以混合使用,但是优先考虑多线程技术。本章中只讲多线程并发技术。
和进程相比,线程具有如下优缺点:
优点:
1.线程启动速度更快,更轻量级。
2.系统资源的开销更小,执行速度快。比如共享内存这种通信方式比任何其他的通信方式都快。
缺点:
有一定难度,使用的时候要注意数据一致性问题。
3. C++11新标准线程库
以往windows下创建新线程的函数:CreateThread();_beginthread();_beginthreadexe()
linux下创建新线程的函数:pthread_create()
此外,以往创建临界区互斥量的函数也不一样。所以以往多线程代码不能跨平台。POSIX thread(pthread)跨平台,但是需要做一番配置,用起来还是不怎么方便。
从C++11新标准以来,C++语言本身增加了对多线程的支持。意味着C++11多线程代码可以跨平台移植。大大减少开发人员工作量。