C++11并发编程(一)——初始C++11多线程库

1 前言
  C++11标准在标准库中为多线程提供了组件,这意味着使用C++编写与平台无关的多线程程序成为可能,而C++程序的可移植性也得到了有力的保证。
  在之前我们主要使用的多线程库要么是属于某个单独平台的,例如:POSIX线程库(Linux),Windows线程库(Windows),还有第三方数据库:Boost线程库。但是且不说性能上的不同,它们都有各自缺点,要么受平台限制无法系统间移植程序,要么需要下载第三方程序包来支持。相比较而言,我们当然更希望使用可移植的官方标准多线程库,这些在C++11中提供了组件,下面我们就一同来学习学习C++11中多线程库吧。
2 并发与并行的区别
  并发指的是两个或多个独立的活动在同一时段内发生。生活中并发的例子并不少,例如在跑步的时候你可能同时在听音乐;在看电脑显示器的同时你的手指在敲击键盘。这时我们称我们大脑并发地处理这些事件,只不过我们大脑的处理是有次重点的:有时候你会更关注你呼吸的频率,而有时候你更多地被美妙的音乐旋律所吸引。这时我们可以说大脑是一种并发设计的结构。这种次重点在计算机程序设计中,体现为某一个时刻只能处理一个操作。
  与并发相近的另一个概念是并行。它们两者存在很大的差别。并行就是同时执行,计算机在同一时刻,在某个时间点上处理两个或以上的操作。判断一个程序是否并行执行,只需要看某个时刻上是否多两个或以上的工作单位在运行。一个程序如果是单线程的,那么它无法并行地运行。利用多线程与多进程可以使得计算机并行地处理程序(当然 ,前提是该计算机有多个处理核心)。
  并发:同一时间段内可以交替处理多个操作:

这里写图片描述

  并行:同一时间段内同时处理多个操作:
这里写图片描述

  第一张图中两个任务队列同时等待一个处理器处理,两个队列可能约定交替着进行被处理,也可能是大家同时竞争被处理(通信)。后一种方式可能引起冲突:因为一个处理器无法同时进行两步操作。但在逻辑上看来,这个处理器是同时处理这两个队列。
  而第二张图中两个任务队列是并行处理,每个队列都有自己的独立处理器(或者核),两个队列中间没有竞争关系,队列中的某个排队者只需等待队列前面的消息处理完成,然后再轮到自己被处理。在物理上,如果是两个核的CPU宏观上看是同时处理这两个任务队列。
  并发的程序设计,提供了一种方式让我们能够设计出一种方案将问题(非必须地)并行地解决。如果我们将程序的结构设计为可以并发执行的,那么在支持并行的机器上,我们可以将程序并行地执行。因此,并发重点指的是程序的设计结构,而并行指的是程序运行的状态。并发编程,是一种将一个程序分解成小片段独立执行的程序设计方法。
3 并发的两种模式
  这里两种模式指的就是我们都知道的多线程并发与多进程并发的两种方法。
 3.1 多进程并发
  多个进程独立地运行,它们之间通过进程间常规的通信渠道传递讯息(信号,套接字,文件,管道等),这种进程间通信不是设置复杂就是速度慢,这是因为为了避免一个进程去修改另一个进程,操作系统在进程间提供了一定的保护措施,当然,这也使得编写安全的并发代码更容易。运行多个进程也需要固定的开销:进程的启动时间,进程管理的资源消耗。
 3.2 多线程并发
  在当个进程中运行多个线程也可以并发。线程就像轻量级的进程,每个线程相互独立运行,但它们共享地址空间,所有线程访问到的大部分数据如指针、对象引用或其他数据可以在线程之间进行传递,它们都可以访问全局变量。进程之间通常共享内存,但这种共享通常难以建立且难以管理,缺少线程间数据的保护。因此,在多线程编程中,我们必须确保每个线程锁访问到的数据是一致的。
4 C++中的并发与多线程
  C++标准并没有提供对多进程并发的原生支持,所以C++的多进程并发要靠其他API——这需要依赖相关平台。
  C++11 标准提供了一个新的线程库,内容包括了管理线程、保护共享数据、线程间的同步操作、低级原子操作等各种类。标准极大地提高了程序的可移植性,以前的多线程依赖于具体的平台,而现在有了统一的接口进行实现。
  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。
    4.1 实例来说
      我们先从一个最简单的也是最常见的单线程程序来看:
include<iostream>
using namespace std;

int main()
{
    cout<<"This is a test!"<<endl;
    return 0;
}

  上面程序就是一个单线程过程,main函数中打印一句话没有多余操作。那我们想另启一个线程来完成这个活怎么做呢?我们看下面的程序:

# include<iostream>
# include<thread>
using namespace std;

void subThread()
{
    cout<<"This is a test!"<<endl;
}

int main()
{
    thread t(subThread); // 创建另外一个线程
    t.join();            // 等待另一个线程执行完毕
}

  在上面程序中我们创建了另一个线程来完成打印工作。每个线程都必须有一个初始函数,新线程的执行开始于初始函数。对于第一段程序来说,它的初始函数是main,对于我们新创建的线程,可以在std::thread()对象的构造函数中指定。
  在第二段程序里,程序由两个线程组成:初始线程始于main,新线程始于subThread。这里将新线程t的初始函数指定为subThread。
  新线程启动之后会与初始进程一并运行,初始线程可以等待或不等待新进程的运行结束——如果需要等待线程,则新线程实例需要使用join(),否则可以使用detach()。如果不等待新线程,则初始线程自顾自地运行到main()结束。
  到此我们就创建了第一个基于C++11多线程库的多线程程序,一般来说并不值得为了如此简单的任务而使用多线程,尤其是在这期间初始线程并没做什么。后面我们会接触更深而更有意义的程序。


  参考文献:
  http://www.cnblogs.com/lpxblog/p/5190438.html
  http://blog.csdn.net/wrx1721267632/article/details/52197849

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值