c++并发编程实战-第1章 c++并发世界

前言

c++11开始支持多线程,使得编写c++多线程程序无需依赖特定的平台,使开发者能够编写可移植的、行为确定的多线程程序代码。

什么是并发

所谓并发,是两个或多个同时独立进行的活动。而计算机中的并发,是指同一个系统中,多个独立活动同时进行。

对于单核处理器,在同一时刻,只能处理一个任务,操作系统将一个时刻分成若干时间片,在每个时间片上执行一个任务,从而实现“伪并发”。对于多核处理器,从硬件上支持并发,在同一时刻内能够运行多个任务,我们称之为硬件并发。

并发的方式:多进程并发、多线程并发。

多进程并发

将一个应用软件拆分成多个独立进程同时运行,这些独立进程都只包含一个主线程。这些独立的进程可以通过操作系统提供的API事件进程间通信(套接字、管道、文件、剪切板)。

优点:相互独立,数据资源互不受影响,容易编写出安全的并发代码。

缺点:开销大,需要为每个进程分配资源;进程间通信速度慢,操作复杂。

多线程并发

多线程并发是指在单一进程中运行多个线程,每个线程独立运行,线程间通过共用相同的地址空间,从而实现在线程间通信。

优点:开销低

缺点:操作复杂

 

 

并发与并行

并发:主要关心的是分离关注点或响应能力。

并行:主要关心的是利用可调配的硬件资源提升大规模数据处理的性能。

为什么需要使用并发

使用并发的主要原因有:分离关注点、提升性能。

分离关注点

编写软件时,分离关注点几乎总是不错的构思:归类相关代码,隔离无关代码,使程序更易于理解和测试,因此所含缺陷很可能更少。可以将一个应用软件划分成如下几个线程:一个UI线程、一个网络线程、一个数据库读写。各个线程之间相互独立,数据访问通过开放接口实现,从而实现各模块代码各自管理。

提升性能

增强性能的并发方式有两种:

  • 第一种是将单一任务分解成多个部分,各自并行运作,从而节省总运行耗时。
  • 第二种是利用并行资源解决规模更大的问题。例如,只要条件适合,便同时处理2个文件,或者10个,甚至20个,而不是每次1个。同时对多组数据执行一样的操作,实际上是采用了数据并行,其着眼点有别于任务并行。采用这种方式处理单一数据所需的时间依旧不变,而同等时间内能处理的数据相对更多。

何时避免使用并发

收益不及代价。多数情况下,采用了并发技术的代码更难理解,编写和维护多线程代码会更劳心费神,并且复杂度增加可能导致更多错误。编写正确运行的多线程代码需要额外的开发时间和相关维护成本,除非潜在的性能提升或分离关注点而提高的清晰度值得这些开销,否则别使用并发技术。

并发与C++多线程

早年C++并不支持多线程,程序员若想使用多线程,必须使用平台提供的API,缺点是依赖特定平台,不便跨平台开发;二是可能依赖特定的处理器架构。

c++11开始支持多线程,规定了内存模型,提供多线程操作,线程管控、保护共享数据,线程间同步以及底层原子操作功能。使得开发者摆脱了平台依赖,仅用C++即可写出高效的代码。

若要实现某项功能,代码可以借助高级工具,或者直接使用底层工具。两种方式的运行开销不同,该项差异叫作抽象损失。在绝大数主流平台,C++多线程是低抽象损失。如果开发者追求极致性能,C++也专门提供了相关接口,开发者可以自行开发出高效的多线程程序。通常不建议。

实例

 1 #include <iostream>
 2 #include <thread>
 3 
 4 void hello()
 5 {
 6     std::cout << "Son Thread " << std::this_thread::get_id() << std::endl;
 7     std::cout << "Hello World!\n";
 8 }
 9 
10 int main()
11 {
12     std::cout << "Main Thread " << std::this_thread::get_id() << std::endl;
13     std::thread th(hello);
14     th.join();
15 }

程序第2行引入头文件<thread>,要使用多线程必须包含该头文件。

在main()函数中,std::this_thread是一个命名空间,在该命名空间中包含获取当前线程相关信息的接口,程序中用get_id()函数获取当前线程的线程ID,用做区分。

要启动一个线程,需要定义一个std::thread对象,该对象需要传递一个可调用对象,作为线程的起始函数,hello()函数就是th线程对象的起始函数。

join()函数的作用的等待子线程执行完毕,主函数会阻塞在此处等待子线程结束。如果不调用join()函数,程序将出现异常情况。

hello()函数是线程的入口函数,线程启动后,最先执行的函数就是hello()函数。

Copyright

本文参考至《c++并发编程实战》 第二版,作者:安东尼·威廉姆斯。本人阅读后添加了自己的理解并整理,方便后续查找,可能存在错误,欢迎大家指正,感谢!

 

posted @ 2023-08-29 19:44  西兰花战士  阅读(123)  评论(0编辑  收藏  举报