C++多线程并发中线程管理
一、何为并发
刚开始接触计算机编程语言时,我们编写一个程序,在main入口函数中调用其它的函数,计算机按我们设定的调用逻辑来执行指令获得结果。如果我们想在程序中完成多个任务,可以将每个任务实现为一个函数然后根据业务逻辑逐个调用。但如果我们想让多个任务几乎同时执行(时间间隔很小,我们感觉是同时执行的一样),比如一边放歌一边显示歌词,恐怕实现起来就会有明显的顿挫感(比如先播放一句歌声,然后显示一行歌词),影响交互体验。
随着我们对计算性能的要求越来越高,多核心处理器很快普及流行。如果我们想让自己开发的程序更高效的运行,自然要充分发挥多核心处理器的优势。在多核心处理器上同时运行多个任务,比在单核心处理器上顺序执行多个任务高效的多。像单片机这种单核心处理器,在任务较多或者多个任务需要几乎同时执行时,也需要应用多任务并发编程提高对包括处理器在内的各硬件资源的利用效率。
1.1 并发与并行
说了这么多,那什么是并发呢?简单来说,并发指的是两个或多个独立的活动在同一时段内发生。并发在生活中随处可见:比如在跑步的时候同时听音乐,在看电脑显示器的同时敲击键盘等。
与并发相近的另一个概念是并行。它们两者存在很大的差别,图示如下:
1.2 硬件并发与任务切换
1.3 多线程并发与多进程并发
前面一直在聊多任务并发,但计算机术语中用得更多的是线程与进程,三者的主要区别如下:
- 任务:从我们认知角度抽象出来的一个概念,放到计算机上主要指由软件完成的一个活动。一个任务既可以是一个进程,也可以是一个线程。简而言之,它指的是一系列共同达到某一目的的操作。例如,读取数据并将数据放入内存中。这个任务可以作为一个进程来实现,也可以作为一个线程(或作为一个中断任务)来实现。
- 进程:资源分配的基本单位,也可能作为调度运行的单位。可以把一个进程看成是一个独立的程序,在内存中有其完备的数据空间和代码空间。一个进程所拥有的数据和变量只属于它自己。例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等。然后,把该进程放人进程的就绪队列。进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行。所以,进程是系统中的并发执行的单位。
- 线程:执行处理器调度的基本单位。一个进程由一个或多个线程构成,各线程共享相同的代码和全局数据,但各有其自己的堆栈。由于堆栈是每个线程一个,所以局部变量对每一线程来说是私有的。由于所有线程共享同样的代码和全局数据,它们比进程更紧密,比单独的进程间更趋向于相互作用,线程间的相互作用更容易些,因为它们本身就有某些供通信用的共享内存:进程的全局数据。
二、如何使用并发
2.1 为什么使用并发
在应用程序中使用并发的原因主要有两个:关注点分离和性能。事实上,我甚至可以说它们差不多是使用并发的唯一原因;当你观察的足够仔细时,一切其他因素都可以归结到这两者之一(或者可能是二者兼有)。
- 关注点分离:通过将相关的代码放在一起并将无关的代码分开,可以使你的程序更容易理解和测试,从而减少出错的可能性。你可以使用并发来分隔不同的功能区域,即使在这些不同功能区域的操作需要在同一时刻发生的情况下;若不显式地使用并发,你要么被迫编写任务切换框架,要么在操作中主动地调用不相关的一段代码。
- 更高效的性能:为了充分发挥多核心处理器的优势,使用并发将单个任务分成几部分且各自并行运行,从而降低总运行时间。根据任务分割方式的不同,又可以将其分为两大类:一类是对同样的数据应用不同的处理算法(任务并行);另一类是用同样的处理算法共同处理数据的几部分(数据并行)。
2.2 在C++中使用并发和多线程
三、C++线程创建
3.1 C++11新标准多线程支持库
- < thread > :包含std::thread类以及std::this_thread命名空间。管理线程的函数和类的声明;
- < atomic > :包含std::atomic和std::atomic_flag类,以及一套C风格的原子类型和与C兼容的原子操作的函数;
- < mutex > :包含了与互斥量相关的类以及其他类型和函数;
- < future > :包含两个Provider类(std::promise和std::package_task)和两个Future类(std::future和std::shared_future)以及相关的类型和函数;
- < condition_variable > :包含与条件变量相关的类,包括std::condition_variable和std::condition_variable_any。
3.2 线程创建的简单示例
//thread1.cpp 创建线程,并观察线程的并发执行与阻塞等待
#include <iostream>
#include <thread>
#include <chrono>
void thread_function(int n)
{
std::thread::id this_id = std::this_thread::get_id(); //获取线程ID
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span> cout <span class="token operator"><<</span> <span class="token string">"Child function thread "</span> <span class="token operator"><<</span> this_id<span class="token operator"><<</span> <span class="token string">" running : "</span> <span class="token operator"><<</span> i<span class="token operator">+</span><span class="token number">1</span> <span class="token operator"><<</span> endl<span class="token punctuation">;</span>std<span class="token operator">::</span>this_thread<span class="token operator">::</span><span class="token function">sleep_for</span><span class="token punctuation">(</span>std<span class="token operator">::</span>chrono<span class="token operator">::</span><span class="token function">seconds</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//进程睡眠n秒</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>cout <span class="token operator"><<</span> <span class="token string">"Child functor thread "</span> <span class="token operator"><<</span> this_id <span class="token operator"><<</span> <span class="token string">" running: "</span> <span class="token operator"><<</span> i<span class="token operator">+</span><span class="token number">1</span> <span class="token operator"><<</span> endl<span class="token punctuation">;</span>std<span class="token operator">::</span>this_thread<span class="token operator">::</span><span class="token function">sleep_for</span><span class="token punctuation">(</span>std<span class="token operator">::</span>chrono<span class="token operator">::</span><span class="token function">seconds</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//进程睡眠n秒</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
Thread_functor thread_functor<span class="token punctuation">;</span> <span class="token comment">//函数对象实例化一个对象</span>
thread <span class="token function">mythread2</span><span class="token punctuation">(</span>thread_functor<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 传递初始函数作为线程的参数</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>mythread2<span class="token punctuation">.</span><span class="token function">joinable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>mythread2<span class="token punctuation">.</span><span class="token function">detach</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 使用detach()函数让子线程和主线程并行运行,主线程也不再等待子线程</span><span class="token keyword">auto</span> thread_lambda <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">int</span> n<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">//lambda表达式格式:[capture list] (params list) mutable exception-> return type { function body }</span>std<span class="token operator">::</span>thread<span class="token operator">::</span>id this_id <span class="token operator">=</span> std<span class="token operator">::</span>this_thread<span class="token operator">::</span><span class="token function">get_id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>cout <span class="token operator"><<</span> <span class="token string">"Child lambda thread "</span> <span class="token operator"><<</span> this_id <span class="token operator"><<</span> <span class="token string">" running: "</span> <span class="token operator"><<</span> i<span class="token operator">+</span><span class="token number">1</span> <span class="token operator"><<</span> endl<span class="token punctuation">;</span>std<span class="token operator">::</span>this_thread<span class="token operator">::</span><span class="token function">sleep_for</span><span class="token punctuation">(</span>std<span class="token operator">::</span>chrono<span class="token operator">::</span><span class="token function">seconds</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//进程睡眠n秒</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>thread <span class="token function">mythread3</span><span class="token punctuation">(</span>thread_lambda<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 传递初始函数作为线程的参数</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>mythread3<span class="token punctuation">.</span><span class="token function">joinable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>mythread3<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 使用join()函数阻塞主线程直至子线程执行完毕</span>std<span class="token operator">::</span>thread<span class="token operator">::</span>id this_id <span class="token operator">=</span> std<span class="token operator">::</span>this_thread<span class="token operator">::</span><span class="token function">get_id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>cout <span class="token operator"><<</span> <span class="token string">"Main thread "</span> <span class="token operator"><<</span> this_id <span class="token operator"><<</span> <span class="token string">" running: "</span> <span class="token operator"><<</span> i<span class="token operator">+</span><span class="token number">1</span> <span class="token operator"><<</span> endl<span class="token punctuation">;</span>std<span class="token operator">::</span>this_thread<span class="token operator">::</span><span class="token function">sleep_for</span><span class="token punctuation">(</span>std<span class="token operator">::</span>chrono<span class="token operator">::</span><span class="token function">seconds</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token function">getchar</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
g++ -Wall -g -std=c++11 -pthread thread1.cpp -o thread1
# -Wall显示所有警告,-g输出调试信息,-std=c++11使用c++11标准编译,-pthread编译使用POSIX thread库文件
C++多线程并发中线程管理相关推荐
- Java-多线程-Future、FutureTask、CompletionService、CompletableFuture解决多线程并发中归集问题的效率对比
转载声明 本文大量内容系转载自以下文章,有删改,并参考其他文档资料加入了一些内容: [小家Java]Future.FutureTask.CompletionService.CompletableFut ...
- java线程池_Java多线程并发:线程基本方法+线程池原理+阻塞队列原理技术分享...
线程基本方法有哪些? 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等. 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等 ...
- 当析构函数遇到多线程 ── C++ 中线程安全的对象回调
陈硕 (giantchen_AT_gmail) 本文 PDF 下载: http://www.cppblog.com/Files/Solstice/dtor_meets_mt.pdf 摘要 编写线程安 ...
- 并发并行多线程并发问题线程安全问题
1.并行(多个线程). 2.并发(一个线程也可以,指的是指的是 一个线程或多个线程上,多个程序之间的多路复用,即看起来是同时) redis就是这种技术,单线程+多路IO复用 3.我们通常说的并发,就是 ...
- java list 多线程add_Java多线程并发中支持并发的list对象
Java多线程并发编程中并发容器第二篇之List的并发类讲解 概述 本文我们将详细讲解list对应的并发容器以及用代码来测试ArrayList.vector以及CopyOnWriteArrayList ...
- java多线程并发及线程池
线程的常用创建方式 1.继承Thread类创建线程类 public class FirstThreadTest extends Thread {public void run(){System.out ...
- 多线程并发中什么是竞争条件?
跟着作者的65节课彻底搞懂Java并发原理专栏,一步步彻底搞懂Java并发原理. 作者简介:笔名seaboat,擅长工程算法.人工智能算法.自然语言处理.计算机视觉.架构.分布式.高并发.大数据和搜索 ...
- 多线程并发或线程安全问题如何解决?
1:通过volatile 关键字修饰变量,可以实现线程之间的可见性, 避免变量脏读的出现,底层是通过限制jvm指令的重排序来实现的 适用于一个线程修改,多个线程读的场景 2:通过synchronize ...
- 【zz】陈硕:当析构函数遇到多线程──C++ 中线程安全的对象回调
需要解决的问题: 析构对象时,如何可知另外的线程正在执行对象的成员的成员函数? 如果保证,执行成员函数期间,对象不会再另外的线程被析构 调用某个对象的成员函数之前,如何得知对象或者? 对象创建:构造时 ...
最新文章
- windows下opencv安装及配置(vs2010环境)
- java基础进阶一:String源码和String常量池
- 三年经验前端社招——腾讯微保
- QML的import目录爬坑记录
- mysql8 修改加密方式_mysql8修改密码加密方式
- 使用OTA绕过AppStore安装App
- java中对象 引用的概念_java中的对象 方法 引用 等一些抽象的概念是什么意思呢?...
- RTT 操作片上flash
- 《深入学习VMware vSphere 6》——1.5 主流服务器的RAID配置
- 在 Windows 下远程桌面连接 Linux - XManager 篇
- (转)AIX rootvg 镜像创建与磁盘更换
- 《非常网管:网络管理从入门到精通(修订版)》一1.4 TCP/IP
- 树分类、线性回归和树回归的感性认知
- 终极算法 机器学习和人工智能如何重塑世界
- 开网店,网店系统的编程语言分析
- Win11资源管理器(文件夹)出现的工具栏怎么隐藏?
- 谢慧敏清晰版. 数学分析习题课讲义.下. 2004
- php开放平台,顺丰开放平台API PHP SDK demo
- java事务 spring事务 分布式事物
- 1162:字符串逆序
热门文章
- 不同路径Python解法
- python中输出菱形_用python打印菱形的实操方法和代码
- python中的垃圾回收机制_python里面的垃圾回收机制
- qemu 安装windows_BIOS+MBR启动引导安装双系统
- 系统启动数据库服务器,linux系统如何启动数据库服务器
- linux在主函数中调用进程,linux 调用进程
- 自己动手写CPU(7)转移指令的实现
- 自己动手写CPU(5)简单算术操作指令实现_1
- Java表示0到200的质因数_java记——循环 求一个数的所有质因数
- python散点图如何设置外边框_如何绘制散点图的外围边框?