C++多线程程序猿

C++11多线程-原子操作(1)

2018-11-25  本文已影响6人  许了

前面我们讲了C++11下的多线程及相关操作,这些操作在绝大多数情况下应该够用了。但在某些极端场合,如需要高性能的情况下,我们还需要一些更高效的同步手段。本节介绍的原子操作是一种lock free的操作,不需要同步锁,具有很高的性能。在化学中原子不是可分割的最小单位,引申到编程中,原子操作是不可打断的最低粒度操作,是线程安全的。C++11中原子类提供的成员函数都是原子的,是线程安全的。
原子操作中最简单的莫过于atomic_flag,只有两种操作:test and set、clear。我们的原子操作就从这种类型开始。

1. std::atomic_flag

C++11中所有的原子类都是不允许拷贝、不允许Move的,atomic_flag也不例外。atomic_flag顾名思议,提供了标志的管理,标志有三种状态:clear、set和未初始化状态。

1.1 atomic_flag实例化

缺省情况下atomic_flag处于未初始化状态。除非初始化时使用了ATOMIC_FLAG_INIT宏,则此时atomic_flag处于clear状态。

1.2 std::atomic_flag::clear

调用该函数将会把atomic_flag置为clear状态。clear状态您可以理解为bool类型的false,set状态可理解为true状态。clear函数没有任何返回值:

void clear(memory_order m = memory_order_seq_cst) volatile noexcept;
void clear(memory_order m = memory_order_seq_cst) noexcept;

对于memory_order我们会在后面的章节中详细介绍它,现在先列出其取值及简单释义

序号 意义
1 memory_order_relaxed 宽松模型,不对执行顺序做保证
2 memory_order_consume 当前线程中,满足happens-before原则。
当前线程中该原子的所有后续操作,必须在本条操作完成之后执行
3 memory_order_acquire 当前线程中,操作满足happens-before原则。
所有后续的操作必须在本操作完成后执行
4 memory_order_release 当前线程中,操作满足happens-before原则。
所有后续的操作必须在本操作完成后执行
5 memory_order_acq_rel 当前线程中,同时满足memory_order_acquire和memory_order_release
6 memory_order_seq_cst 最强约束。全部读写都按顺序执行

1.3 test_and_set

该函数会检测flag是否处于set状态,如果不是,则将其设置为set状态,并返回false;否则返回true。


test_and_set是典型的read-modify-write(RMW)模型,保证多线程环境下只被设置一次。下面代码通过10个线程,模拟了一个计数程序,第一个完成计数的会打印"win"。
#include <atomic>    // atomic_flag
#include <iostream>  // std::cout, std::endl
#include <list>      // std::list
#include <thread>    // std::thread

void race(std::atomic_flag &af, int id, int n) {
    for (int i = 0; i < n; i++) {
    }
    // 第一个完成计数的打印:Win
    if (!af.test_and_set()) {
        printf("%s[%d] win!!!\n", __FUNCTION__, id);
    }
}

int main() {
    std::atomic_flag af = ATOMIC_FLAG_INIT;

    std::list<std::thread> lstThread;
    for (int i = 0; i < 10; i++) {
        lstThread.emplace_back(race, std::ref(af), i + 1, 5000 * 10000);
    }

    for (std::thread &thr : lstThread) {
        thr.join();
    }

    return 0;
}

程序输出如下(每次运行,可能率先完成的thread不同):

race[7] win!!!
上一篇
C++11多线程-线程局部存储
目录 下一篇
C++11多线程-原子操作(2)

上一篇下一篇

猜你喜欢

热点阅读