c++ 11 atomic的应用

定义

c++ atomic 是使数据保持原子性,主要应用在多线程场景。
特化种提供了很多基础数据类型的别名:

atomic_bool
atomic_char
atomic_ulong
...

对于结构的原子特化需要结构满足:

主 std::atomic 模板可用任何满足可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 的可平凡复制 (TriviallyCopyable) 类型 T 实例化

例子

文件test_atmoic.cc

#include <atomic>
#include <iostream>
#include <memory>
using namespace std;

class A {
public:
  struct pair {
    uint64_t first = 1;
    uint64_t second = 2;
    pair(uint64_t a, uint64_t b) {
      first = a;
      second = b;
    }
    pair() {}
  };
  std::atomic<pair> one;
};

int main() {
  A aa;
  aa.one.store(A::pair());
  A::pair pp = aa.one.load();
  std::cout << pp.first << ' ' << pp.second << endl;
  return 0;
}

编译时候要加-latomic 库
g++ test_atomic.cc -std=c++11 -latomic

使用atomic的CAS

https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange

If those are bitwise-equal, replaces the former with desired (performs read-modify-write operation). Otherwise, loads the actual value stored in *this into expected (performs load operation).

std::atomic<T>::compare_exchange_weak
std::atomic<T>::compare_exchange_strong

两者区别:
weak 可能会有虚假失败,适合在while循环中。虚假失败是因为比较方式是按位比较,如果数据结构有pad的,可能会失败;
strong 会检查虚假失败,但是性能劣于weak
https://stackoverflow.com/questions/25199838/understanding-stdatomiccompare-exchange-weak-in-c11

示例1 无锁实现

#include <atomic>

template <typename T> struct node {
  T data;
  node *next;
  node(const T &data) : data(data), next(nullptr) {}
};

template <typename T> class stack {
  std::atomic<node<T> *> head;

public:
  void push(const T &data) {
    node<T> *new_node = new node<T>(data);
    new_node->next = head.load(std::memory_order_relaxed);
    while (!head.compare_exchange_weak(new_node->next, new_node,
                                       std::memory_order_release,
                                       std::memory_order_relaxed))
      ; // the body of the loop is empty
  }
};

int main() {
  stack<int> s;
  s.push(1);
  s.push(2);
  s.push(3);
}

示例2 多线程竞争访问临界区,并只需要赋值一次

  auto t = a.load();
  if(a.compare_exchange_strong(t, 1, std::memory_order_relaxed)) {
  ...
  }else{
  ...
  }

示例3 mysql中互斥量的实现

void spin_and_try_lock(uint32_t max_spins, uint32_t max_delay,
                       const char *filename, uint32_t line) UNIV_NOTHROW {
  uint32_t n_spins = 0;
  uint32_t n_waits = 0;
  const uint32_t step = max_spins;

  for (;;) {
    /* If the lock was free then try and acquire it. */

    if (is_free(max_spins, max_delay, n_spins)) {
      if (try_lock()) {
        break;
      } else {
        continue;
      }

    } else {
      max_spins = n_spins + step;
    }

    ++n_waits;

    os_thread_yield();

    if (wait(filename, line, 4)) {
      n_spins += 4;

      break;
    }
  }

  m_policy.add(n_spins, n_waits);
}

bool is_free(uint32_t max_spins, uint32_t max_delay,
             uint32_t &n_spins) const UNIV_NOTHROW {
  ut_ad(n_spins <= max_spins);

  do {
    if (!is_locked()) {
      return (true);
    }

    ut_delay(ut_rnd_interval(0, max_delay));

    ++n_spins;

  } while (n_spins < max_spins);

  return (false);
}

bool try_lock() UNIV_NOTHROW {
  bool expected = false;
  return (m_lock_word.compare_exchange_strong(expected, true));
}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值