未来芯片制造,如果突破不了 5nm 极限,则 CPU 性能的提升,可能会依赖于三维集成技术,将多个 CPU 核集成在一起,使得多核系统越来越普遍。

以前的 C++ 多线程,一是受限于平台,多借助于封装好的 APIs 来完成,例如:POSIX threads,Windows threads 等;二是受限于单核系统,本质上都是“伪多线程”:通过线程调度,使得单核系统进行任务的切换,形成多线程的假象。

新的 C++11 标准,在语言层面上实现了多线程,其库中提供了相关组件,使得跨平台编写多线程 cpp 程序成为可能,最终能够在多核系统中实现真正的并行计算

1  并发 (concurrency)

1.1 并发与并行

计算机中的并发,指的是在单一系统中,同时执行多个独立的活动。对于多核系统,它们在同一时刻进行的活动,则称为并行

通俗的理解:当有两个人都在边吃饭边看电视时,对于一个人而言,吃饭和看电视就是并发,对于两个人而言,他们在同一时刻进行的活动,可称为并行。

1) 单核的任务切换 (task switching)

2) 双核的并行执行 (parallel execution)

1.2 线程与进程

如果将进程比作一套房子,那么住在房子里的人,其从事的各种活动 (比如,厨房做饭,客厅吃饭,卧室看电视),就是一个个的线程。现在又搬来一个人,则当两个人都在房子里,做着各自的活动时,程序便由以前的单线程变为了多线程

有的房间 (比如客厅) 两个人都可以同时进出,这代表着进程中某些内存空间是共享的,每个线程都可以使用这些共享内存。有的房间 (比如厕所) 一次只能容纳一个人,先进去的把门锁上,后到的人看到锁,就在外面等待,直到先进去的人把锁打开,这就是“互斥核” (mutex)

在应用程序中,具体利用到并发编程的,一是多进程并发,二是多线程并发,如下图:

       

(1) 多进程并发                     (2) 多线程并发

2  程序示例

  实现多线程需要 1) 头文件 <thread>   2) 单独的线程函数 threadFunc()   3)线程对象 thread t(threadFunc)   4)等待线程 join()

#include <thread>
#include <iostream> void threadFunc()
{
std::cout << "This is a thread!" << std::endl;
} int main()
{
std::thread t(threadFunc);
t.join(); std::cout << "This is main program!" << std::endl; return ;
}

输出结果为:

This is a thread!
This is main program!

当使用 t.detach() 来代替 t.join() 时,主线程 main 不会等待新线程 t(threadFunc),只会独自运行到程序结束。

3  任务代替线程

3.1  两个问题

1) 线程耗尽 (exhaustion)

 软件线程是一种有限的资源,当创建的线程数量多于系统所能够提供的,一个异常 std::system_error 就会抛出,程序便会终止。

2) 线程超额 (oversubscription)

 当等待运行的线程 (ready-to-run) 多于系统硬件线程 (hardware threads) 时,线程调度器会为每个软件线程在硬件线程上分配时间片 (time-slice)。若一个线程的时间片结束,另一个线程的时间片刚开始时,上下文的切换 (context switch) 就会被执行。对于多核系统,当线程从一个 CPU 被切换到另一个 CPU 中时,会造成很大的资源消耗。

3.2  基于任务 (task-based)

基于线程编程 (thread-based),必须手动管理上面的两个问题,增加了编程的难度。

基于任务编程 (task-based),通过 std::async,可将问题交由 C++标准库处理,简化了程序。

1)  头文件 <future>

2) 单独的任务函数 taskFunc1 和 taskFunc2

3) 异步任务对象 auto fut1 = std::async(taskFunc1)

4) 获取任务函数返回值 fut1.get()

#include <iostream>
#include <thread>
#include <future> std::string taskFunc1()
{
std::string str = "This is task1";
return str;
} std::string taskFunc2()
{
std::string str = " and task2";
return str;
} int main()
{
auto fut1 = std::async(taskFunc1);
auto fut2 = std::async(taskFunc2); std::cout << fut1.get() + fut2.get() << std::endl << "This is main program" << std::endl; return ;
}

输出结果为:

This is task1 and task2
This is main program

小结:

1) thread-based programming needs manual management of thread exhaustion, oversubscription, load balancing, and adaptation to new platforms.

2) task-based programming handles most of these issues via std::async with the default launch policy

参考资料:

<C++ Concurrency in Action> chapter 1

<Effecctive Modern C++>  chapter 7

C++11 之 并发编程 (一)的更多相关文章

  1. 11 go并发编程-上

    其他编程语言并发编程的效果 并发编程可以让开发者实现并行的算法以及编写充分利用多核处理器和多核性能的程序.在当前大部分主流的编程语言里,如C,C++,java等,编写维护和调试并发程序相比单线程程序而 ...

  2. C++11 (多线程)并发编程总结

    | 线程 std::thread 创建std::thread,一般会绑定一个底层的线程.若该thread还绑定好函数对象,则即刻将该函数运行于thread的底层线程. 线程相关的很多默认是move语义 ...

  3. 并发编程: c++11 thread(Func, Args...)利用类成员函数创建线程

    c++11是VS2012后支持的新标准,为并发编程提供了方便的std::thread. 使用示例: #include <thread> void thread_func(int arg1, ...

  4. 【Java并发编程】11、volatile的使用及其原理

    一.volatile的作用 在<Java并发编程:核心理论>一文中,我们已经提到过可见性.有序性及原子性问题,通常情况下我们可以通过Synchronized关键字来解决这些个问题,不过如果 ...

  5. c++ 11开始语言本身和标准库支持并发编程

    c++ 11开始语言本身和标准库支持并发编程,意味着真正要到编译器从语言和标准库层面开始稳定,估计得到17标准出来.14稳定之后的事情了,根据历史经验,新特性的引入到稳定被广泛采用至少要一个大版本的跨 ...

  6. 11、Java并发编程:并发容器之CopyOnWriteArrayList

    Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...

  7. C++11 并发编程基础(一):并发、并行与C++多线程

    正文 C++11标准在标准库中为多线程提供了组件,这意味着使用C++编写与平台无关的多线程程序成为可能,而C++程序的可移植性也得到了有力的保证.另外,并发编程可提高应用的性能,这对对性能锱铢必较的C ...

  8. 并发编程学习笔记(11)----FutureTask的使用及实现

    1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ...

  9. C++11 并发编程库

    C++11 并发编程 C++11 新标准中引入了几个头文件来支持多线程编程,他们分别是: <atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_f ...

随机推荐

  1. C++实现邮件群发的方法

    这篇文章主要介绍了C++实现邮件群发的方法,较为详细的分析了邮件发送的原理与C++相关实现技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了C++实现邮件群发的方法.分享给大家供大家参考.具 ...

  2. 大叔也说并行和串行`性能提升N倍(N由操作系统位数和cpu核数决定)

    返回目录 并行是.net4.5主打的技术,同时被封装到了System.Threading.Tasks命名空间下,对外提供了静态类Parallel,我们可以直接使用它的静态方法,它可以并行一个委托数组, ...

  3. CSS侧边栏,ng-click定义选中事件

    本篇小随笔,记录下侧边栏的写法和ng-click点击选中事件.因为这个工程不让引用jQuery.所以ng-click选中事件用了一个比较笨的方法实现的. 下面是HTML页面 按 Ctrl+C 复制代码 ...

  4. linux lin命令

    ln是linux中又一个非常重要命令,它的功能是为某一个文件在另外一个位置建立一个同不的链接,这个命令最常用的参数是-s,具体用法是:ln –s 源文件 目标文件. 当我们需要在不同的目录,用到相同的 ...

  5. Maven命令行使用:mvn clean package(打包)

    先把命令行切换到Maven项目的根目录,比如:/d/xxxwork/java/maven-test,然后执行命令:  mvn clean package 执行结果如下: [INFO] Scanning ...

  6. (原)3.2 Zookeeper应用 - 数据的发布与订阅

    本文为原创文章,转载请注明出处,谢谢 数据的发布与订阅 1.应用 服务端监听数据改变,客户端创建/更新节点数据,客户端提供数据,服务端处理 2.原理 客户端监控节点数据改变事件(例如配置信息,下图的c ...

  7. asp.net mvc 中 一种简单的 URL 重写

    asp.net mvc 中 一种简单的 URL 重写 Intro 在项目中想增加一个公告的功能,但是又不想直接用默认带的那种路由,感觉好low逼,想弄成那种伪静态化的路由 (别问我为什么不直接静态化, ...

  8. php中用foreach改变数组的值的问题

    翻到PHP文档的foreach那页这样写道: “foreach 语法结构提供了遍历数组的简单方式.foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误 ...

  9. IBM实习

    来到北京,进入IBM实习已经好多天了,两个月的暑假,两个月夏日在这里度过了,并将在未来个一个月里面,仍将在这里走过,但是我却一无所成,现在仍然只在徘徊中游走,丹迪什么时候能真正懂得实习的难得可贵,懂得 ...

  10. 获取WIFI密码

    在十年前,我还在上初中,班上只有极少数的富二代用得起手机:几年后诺基亚.摩托罗拉.三星手机开始盛行:近些年,安卓.苹果系统手机占据了基本整个市场,WIFI出变得越来越重要. Wifi万能钥匙数据库存储 ...