C++(C11)

并发与并行

并发的程序设计,提供了一种方式让我们能够设计出一种方案将问题(非必须地)并行地解决。如果我们将程序的结构设计为可以并发执行的,那么在支持并行的机器上,我们可以将程序并行地执行。因此,并发重点指的是程序的设计结构,而并行指的是程序运行的状态。并发编程,是一种将一个程序分解成小片段独立执行的程序设计方法。

C++标准并没有提供对多进程并发的原生支持,所以C++的多进程并发要靠其他API——这需要依赖相关平台。


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。

Thread

default (1)
thread() noexcept;
initialization (2)
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
copy [deleted] (3)
thread (const thread&) = delete;
move (4)
thread (thread&& x) noexcept;
  • (1). 默认构造函数,创建一个空的 thread 执行对象。
  • (2). 初始化构造函数,创建一个 thread对象,该 thread对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
  • (3). 拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
  • (4). move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
  • 注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.

智能指针

shared_ptr

shared_ptr 是一个标准的共享所有权的智能指针, 允许多个指针指向同一个对象. 定义在 memory 文件中(非memory.h), 命名空间为 std.

  shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的), 在使用引用计数的机制上提供了可以共享所有权的智能指针, 当然这需要额外的开销:
  (1) shared_ptr 对象除了包括一个所拥有对象的指针外, 还必须包括一个引用计数代理对象的指针.
  (2) 时间上的开销主要在初始化和拷贝操作上, *和->操作符重载的开销跟auto_ptr是一样.
  (3) 开销并不是我们不使用shared_ptr的理由, 永远不要进行不成熟的优化, 直到性能分析器告诉你这一点.

  使用方法:

可以使用模板函数 make_shared 创建对象, make_shared 需指定类型('<>'中)及参数('()'内), 传递的参数必须与指定的类型的构造函数匹配. 如:
  std::shared_ptr<int> sp1 = std::make_shared<int>(10);
  std::shared_ptr<std::string> sp2 = std::make_shared<std::string>("Hello c++");
也可以定义 auto 类型的变量来保存 make_shared 的结果.
  auto sp3 = std::make_shared<int>(11);
  printf("sp3=%d\n", *sp3);
  auto sp4 = std::make_shared<std::string>("C++11");
  printf("sp4=%s\n", (*sp4).c_str());

原子指令

原子指令是对软件不可再分的指令

原子指令 (x均为std::atomic<int>) 作用
x.load() 返回x的值。
x.store(n) 把x设为n,什么都不返回。
x.exchange(n) 把x设为n,返回设定之前的值。

x.compare_exchange_strong(expected_ref, desired)

若x等于expected_ref,则设为desired,返回成功;否则把最新值写入expected_ref,返回失败。
x.compare_exchange_weak(expected_ref, desired) 相比compare_exchange_strong可能有spurious wakeup
x.fetch_add(n), x.fetch_sub(n), x.fetch_xxx(n) x += n, x-= n(或更多指令),返回修改之前的值。

race condition、ABA problem、memory fence

猜你喜欢

转载自my.oschina.net/u/347414/blog/1790444
C11