什么是原子变量
原子变量是在多线程访问状态下不会导致数据竞争的变量。
原子变量保证多线程安全,效率会比互斥量好一些。
主要用于无锁编程。
实现
硬件层面:通过添加原子指令以保证对单个变量操作的原子性。
软件层面:使用互斥锁或者自旋锁保证只有拥有锁的线程,变量会被该线程访问或修改。
GCC下原子变量的定义
这是一个整型模板的源码定义和成员函数
/// Explicit specialization for int.
template<>
struct atomic<int> : __atomic_base<int>
{
typedef int __integral_type;
typedef __atomic_base<int> __base_type;
atomic() noexcept = default;
~atomic() noexcept = default;
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
using __base_type::operator __integral_type;
using __base_type::operator=;
#if __cplusplus >= 201703L
static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2;
#endif
};
bool is_lock_free() const noexcept { return _M_base.is_lock_free(); }
#if __cplusplus >= 201703L
static constexpr bool is_always_lock_free = ATOMIC_BOOL_LOCK_FREE == 2;
#endif
void
store(bool __i, memory_order __m = memory_order_seq_cst) noexcept
{ _M_base.store(__i, __m); }
bool
load(memory_order __m = memory_order_seq_cst) const noexcept
{ return _M_base.load(__m); }
bool
exchange(bool __i, memory_order __m = memory_order_seq_cst) noexcept
{ return _M_base.exchange(__i, __m); }
bool
compare_exchange_weak(bool& __i1, bool __i2, memory_order __m1,
memory_order __m2) noexcept
{ return _M_base.compare_exchange_weak(__i1, __i2, __m1, __m2);
bool
compare_exchange_strong(bool& __i1, bool __i2, memory_order __m1,
memory_order __m2) noexcept
{ return _M_base.compare_exchange_strong(__i1, __i2, __m1, __m2); }
atomic相关的成员函数
构造函数
atomic() noexcept = default; //对象处于未初始化状态
constexpr atomic (T val) noexcept; //使用val初始化对象
atomic (const atomic&) = delete; //无法复制/移动对象
is_lock_free()
bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;
//提示该原子对象是否为无锁对象,无锁对象不会导致其他线程在访问时被阻塞
store函数
void store (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;
void store (T val, memory_order sync = memory_order_seq_cst) noexcept;
//修改包含的值,将包含的值替换为val,该操作是原子操作
std::atomic<int> foo (0);
foo.store(x,std::memory_order_relaxed); // set value atomically
//修改值是原子操作
load函数
T load (memory_order sync = memory_order_seq_cst) const volatile noexcept;
T load (memory_order sync = memory_order_seq_cst) const noexcept;
//读取值同样是原子操作
exchange函数
T exchange (T val, memory_order sync = memory_order_seq_cst) volatile noexcept;
T exchange (T val, memory_order sync = memory_order_seq_cst) noexcept;
//用val修改原子变量包含的值,并且使用返回修改前的值。
atomic<int> x(1);
cout << x.exchange(2) << endl; // cout 1
cout << x.exchange(3) << endl; // cout 2
compare_exchange_weak函数
bool compare_exchange_weak (T& expected, T val,memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,memory_order sync = memory_order_seq_cst) noexcept;
bool compare_exchange_weak (T& expected, T val,memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_weak (T& expected, T val,memory_order success, memory_order failure) noexcept;
//比较和交换值,如果为true,则用like替换为包含的值
//false,则替换为包含的值
函数尝试更新目标值,在某些情况下可能会返回失败,即使更新已经发生了。
如果当前值等于except,则修改为val,返回成功,但有时候成功修改了也会修改为失败,这种情况称为伪失败。
memory_order_seq内存控制顺序,暂定,不是很懂。
compare_exchange_strong函数
互斥锁模拟原子变量
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
template <typename T>
class MyAtomic
{
public:
MyAtomic(T value)
: m_value(value)
{
}
void operator=(T &ans)
{
m_mutex.lock();
m_value = ans;
m_mutex.unlock();
}
void operator++()
{
m_mutex.lock();
m_value++;
m_mutex.unlock();
}
void operator++(int)
{
m_mutex.lock();
++m_value;
m_mutex.unlock();
}
// 不保证线程安全
T getValue()
{
return m_value;
}
friend ostream &operator<<(ostream &cout, MyAtomic<T> &MAT)
{
cout << MAT.getValue();
return cout;
}
private:
T m_value;
mutex m_mutex;
};
template <typename T>
ostream &operator<<(ostream &cout, MyAtomic<T> &MAT)
{
cout << MAT.getValue();
return cout;
}
MyAtomic<int> x = 0;
void threadWorker()
{
for (int i = 0; i < 100000; ++i)
++x;
}
int main()
{
cout << min(1, 3) << endl;
thread thread1(threadWorker);
for (int i = 0; i < 100000; ++i)
++x;
thread1.join();
return 0;
}