read write spinlock

发一个自己基于 C++11 写的 read write spinlock,在 MinGW 4.8.2 (gcc 4.8 全面支持c++ 11,但由于gcc windows平台 libstdc++ 目前还不支持 thread,所以用 boost 1.49 及以上版本作为thread库)。

目前在 Xeon E5606 (4核8线程) Win2008 x64平台上测试通过,但还需要在内存弱序的arm上做进一步测试

代码 spinlock.cpp

#include<atomic>
#include<cassert>

#define SPIN_LOCK_UNLOCK 0
#define SPIN_LOCK_WRITE_LOCK -1

using std::atomic;
using std::atomic_int;
using std::atomic_store_explicit;
using std::atomic_load_explicit;
using std::atomic_compare_exchange_weak_explicit;
using std::memory_order_relaxed;
using std::memory_order_acquire;
using std::memory_order_release;
 
typedef atomic<int> spinlock_t;

void rwlock_init(spinlock_t &l)
{
    atomic_store_explicit(&l, SPIN_LOCK_UNLOCK, memory_order_relaxed);
}

void read_lock(spinlock_t &l)
{
    int expected;
    int desired;

    while(true)
    {
        expected = atomic_load_explicit(&l, memory_order_relaxed);

        if(expected >= 0)
        {
            desired = 1 + expected;
            if(atomic_compare_exchange_weak_explicit(&l, &expected, desired, memory_order_relaxed, memory_order_relaxed))
                break; // success
        }
    }

    atomic_thread_fence(memory_order_acquire); // sync
}

void read_unlock(spinlock_t &l)
{
    int expected;
    int desired;

    while(true)
    {
        expected = atomic_load_explicit(&l, memory_order_relaxed);

        if(expected > 0)
        {
            desired = expected - 1;

            atomic_thread_fence(memory_order_release); // sync
            if(atomic_compare_exchange_weak_explicit(&l, &expected, desired, memory_order_relaxed, memory_order_relaxed))
                break; // success
        }
        else
        {
            assert(false);
        }
    }
}

void write_lock(spinlock_t &l)
{
    int expected;
    int desired;

    while(true)
    {
        expected = atomic_load_explicit(&l, memory_order_relaxed);

        if(expected == SPIN_LOCK_UNLOCK)
        {
            desired = SPIN_LOCK_WRITE_LOCK;
            if(atomic_compare_exchange_weak_explicit(&l, &expected, desired, memory_order_relaxed, memory_order_relaxed))
                break; // success
        }
    }

    atomic_thread_fence(memory_order_release); // sync
}

void write_unlock(spinlock_t &l)
{
    int expected;
    int desired;

    while(true)
    {
        expected = atomic_load_explicit(&l, memory_order_relaxed);

        if(expected == SPIN_LOCK_WRITE_LOCK)
        {
            desired = SPIN_LOCK_UNLOCK;

            atomic_thread_fence(memory_order_release); // sync
            if(atomic_compare_exchange_weak_explicit(&l, &expected, desired, memory_order_relaxed, memory_order_relaxed))
                break; // success
        }
        else
        {
            assert(false);
        }
    }
}

//#include<thread>
#include<boost/thread.hpp>
#include<iostream>

spinlock_t g_lock;
long g_total;
const int count = 5000;

void add_job()
{
    for(int i = 0; i < count; ++i)
    {
        write_lock(g_lock);
        ++g_total;
        std::cout << "Thread ++ " << boost::this_thread::get_id() << std::endl;
        write_unlock(g_lock);
    }
}

void read_job()
{
    for(int i = 0; i < count; ++i)
    {
        read_lock(g_lock);
        std::cout << g_total << std::endl;;
        read_unlock(g_lock);
    }
}

int main()
{
    g_total = 0;
    rwlock_init(g_lock);


    boost::thread th1(add_job);
    boost::thread th2(add_job);

    boost::thread th3(read_job);
    boost::thread th4(read_job);
    boost::thread th5(read_job);

    th1.join();
    th2.join();
    th3.join();
    th4.join();
    th5.join();

    std::cout << "The total: " << g_total << std::endl;
}

编译命令行:

g++  -std=c++11 -Wall -O2 spinlock.cpp -I/d/Sources/boost_1_55_0 -L /d/Sources/boost_1_55_0/stage/lib/ -lboost_thread-mgw48-mt-1_55 -lboost_system-mgw48-mt-1_55

 

其它类型 spin lock

1)最简单(非读写)的 spinlock 可以参考 boost::atomic 里面示例  ;

2)Linux kernel 中还有一类 write prefer 的spin lock,了解原理后也很容易实现,原理可以参考文档 Linux Kernel Development 3rd。

posted on 2014-01-15 17:51  JesseFang  阅读(611)  评论(0编辑  收藏  举报