通过atomic_flag简单自旋锁实现简单说明标准库中锁使用的memory_order

在使用标准库中的加锁机制时,例如我们使用std::mutex,写了如下的代码(下面的代码使用condition_variable可能更合适)

std::mutex g_mtx;
int g_resNum;
// and how to get the resource
...

// 线程1使用如下代码:
{
    std::lock_guard<std::mutex> guard(g_mtx);
    // prepare the resource
    ...
    // set the resource num
    g_resNum = ...;
}

// 线程2使用如下的代码:
{
    std::lock_guard<std::mutex> guard(g_mtx);
    // check the g_resNum
    if (g_resNum > 0)
    {
        ...
    }
}

 我们知道如果先运行线程1的代码,也就是说线程1获得了锁,进行了准备资源的操作。然后运行线程2,也就是说线程2之后获得了锁,可以知道线程1加锁区域的代码已经执行完毕,而且对线程2可见,我们可以放心的使用线程1中设置的资源。这里面的原因是

标准库在实现std::mutex过程中使用了memory_order。http://en.cppreference.com/w/cpp/atomic/memory_order 中的描述如下:

Acquire operation
Atomic load with memory_order_acquire or stronger is an acquire operation. The lock() operation on a Mutex is also an acquire operation. 

Release operation
Atomic store with memory_order_release or stronger is a release operation. The unlock() operation on a Mutex is also a release operation. 

C++ atomic中对Acquire- Release ordering的简单介绍如下:

If an atomic store in thread A is tagged memory_order_release and an atomic load in thread B from the same variable is tagged memory_order_acquire, all memory writes (non-atomic and relaxed atomic) that happened-before the atomic store from the point of view of thread A, become visible side-effects in thread B, that is, once the atomic load is completed, thread B is guaranteed to see everything thread A wrote to memory.

关于memory_order的简单介绍就到这里,下面我用一个很简单的spinlock的实现来简单说明一下memory_order的使用:

class spinlock_mutex
{
    std::atomic_flag flag;
public:
    spinlock_mutex() :
        flag(ATOMIC_FLAG_INIT)
    {}

    void lock()
    {
        while(flag.test_and_set(std::memory_order_acquire));
    }

    bool try_lock()
    {
        if (flag.test_and_set(std::memory_order_acquire))
            return false;

        return true;
    }

    void unlock()
    {
        flag.clear(std::memory_order_release);
    }
};

上述spinlock实现存在性能上的问题,网上有关于这个实现问题的讨论,参考网址:https://www.zhihu.com/question/55764216

希望能给初学C++标准库多线程的程序员有所启示。

原文地址:https://www.cnblogs.com/albizzia/p/8550093.html