c++11 boost - 竞争 atomic、mutex

2018-07-13 22:17:52

atomic 实现了原子操作库,让我们完全摆脱并发竞争读写变量的困扰。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
using namespace std;

#include <boost/atomic.hpp>
using namespace boost;

void case1()
{
    atomic<int> a(10);
    assert(a == 10);

    atomic<long> l;
    l = 100L;
    cout << l << endl;

    atomic<double> d(2.414);
    cout << d << endl;
}

//store()等价于operator=,load()等价于隐式转换,原子方式存取值
void case2()
{
    atomic<bool> b{false};
    assert(!b.load());

    b.store(true);
    assert(b);

    atomic<int> n(100);
    assert(n.exchange(200) == 100);  //原子地交换
    assert(n == 200);
}

//比较并交换
void case3()
{
    atomic<long> l(100);

    long v = 100;
    if (l.compare_exchange_weak(v, 313))  //速度快,但是可能成功了返回false
    {
        assert(l == 313 && v == 100);
    }

    v = 200;
    auto b = l.compare_exchange_strong(v, 99);
    assert(!b && v == 313);

    l.compare_exchange_weak(v, 99);
    assert(l == 99 && v == 313 );
}

#include <boost/utility.hpp>
void case4()
{
    atomic<int> n(100);

    assert(n.fetch_add(10) == 100);  //加法
    assert(n == 110);

    assert(++n == 111);
    assert(n++ ==111);
    assert(n == 112);

    assert((n -= 10) == 102);  //相当于fetch_sub

    atomic<int> b{BOOST_BINARY(1101)};

    auto x = b.fetch_and(BOOST_BINARY(0110));  //逻辑与
    assert(x == BOOST_BINARY(1101) &&
           b == BOOST_BINARY(0100));
    assert((b |= BOOST_BINARY(1001))   //相当于fetch_or
            == BOOST_BINARY(1101));
}

void case5()
{
    atomic<bool> b{true};
    assert(b);

    b = false;
    assert(!b.load());

    auto x = b.exchange(true);
    assert(b && !x);
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
}
[root@192 c++]# g++ -std=c++11 main.cpp 
[root@192 c++]# ./a.out 
100
2.414


mutex 互斥量是一种用于线程的同步的手段,它可以防止多线程环境里防止多个线程同时操作同一个资源。

null_mutex:无任何锁定功能的互斥量,空对象模式的引用。
mutex:独占式互斥量。
timed_mutex:独占式互斥量,不过提过超时功能。
recursive_mutex:可以多次锁定,相应的需要多次解锁。
recursive_mutex:同上,提供超时功能。
shared_mutex:共享互斥量,又称读写锁。

编译的时候如果报如下错,记得带上编译选项。

/usr/bin/ld: /tmp/cc4H7ozR.o: undefined reference to symbol 'pthread_condattr_setclock@@GLIBC_2.3.3'
/usr/lib64/libpthread.so.0: error adding symbols: DSO missing from command line
undefined reference to `boost::chrono::steady_clock::now()
-lboost_thread -lboost_system -lboost_chrono -lpthread

lock_guard 类在退出作用域时能自动释放锁。
unique_lock 类似于 lock_guard,但是功能更复杂,内部使用指针来保存互斥量。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
using namespace std;

#define BOOST_THREAD_VERSION 5
#include <boost/ref.hpp>
#include <boost/thread.hpp>
using namespace boost;

#include <boost/chrono.hpp>
using namespace boost::chrono;

//定义c++11字面值
seconds operator"" _s(unsigned long long n)
{
    return seconds(n);
}

milliseconds operator"" _ms(unsigned long long n)
{
    return milliseconds(n);
}

void case1()
{
    mutex mu;
    try
    {
        mu.lock();  //锁定互斥量
        cout  << "some operations" << endl;  //操作共享资源
        mu.unlock();  //解锁
    }
    catch (...)
    {
    	//保证能解锁
        mu.unlock();
    }

    {
        lock_guard<mutex> g(mu);  //锁定互斥量
        cout  << "some operations" << endl;  
        
        //退出作用域自动解锁
    }
}

void case2()
{
    timed_mutex mu;

    auto flag = mu.try_lock_for(100_ms);  //如果被别人锁住了,试图等待100ms让别人释放锁
    //成功锁住返回true
    if(flag)
    {
        cout << "lock timed mutex" << endl;
        mu.unlock();
    }

    {
        if(mu.try_lock_for(100_ms))
        {
            lock_guard<timed_mutex> g(mu, adopt_lock);  //已经上锁,此时不会再次上锁
            cout << "lock timed mutex" << endl;
        }
    }
}

#include <boost/thread/lock_factories.hpp>

template <typename Lockable, typename D>
unique_lock<Lockable> my_make_lock(Lockable& mtx, D d)
{
    return unique_lock<Lockable> (mtx, d);
}

void case3()
{
    mutex mu;

    {
        auto g = make_unique_lock(mu);  //上锁,退出作用域后自动解锁
        assert(g.owns_lock());
        cout  << "some operations" << endl;
    }

    {
        auto g = make_unique_lock(mu, defer_lock); //暂不锁定
        assert(!g);

        assert(g.try_lock());  //尝试锁定
        assert(g);

        cout  << "some operations" << endl;
    }

    timed_mutex tm;
    //typedef unique_lock<timed_mutex> lock_type;

    {
        //lock_type g(tm, 100_ms);
        auto g = my_make_lock(tm, 100_ms);  //100ms超时时间内尝试锁定
        if(g)
        {
            cout << "lock timed mutex" << endl;
        }
    }

    auto g = make_unique_locks(mu, tm);  //同时锁定多个互斥量
    assert(std::tuple_size<decltype(g)>::value == 2);
}

//锁适配器
#include <boost/atomic.hpp>
#include <boost/thread/lockable_adapter.hpp>
class account final : public lockable_adapter<mutex>
{
private:
    boost::atomic<int> m_money{0};
public:
    account() {}
    ~account() {}
public:
    int sum() const
    {
        return m_money;
    }

    void withdraw(int x)
    {
        m_money -= x;
    }

    void deposit(int x)
    {
        m_money += x;
    }
};

void case4()
{
    account a;

    {
        auto g = make_unique_lock(a);   //锁定对象
        a.deposit(100);
        a.withdraw(20);
        assert(a.sum() == 80);
    }

    {
        auto b = make_unique_lock(a, try_to_lock);  //尝试锁定对象
        if(b)
        {
            a.withdraw(a.sum());
            assert(a.sum() == 0);
        }
    }
}

void case5()
{
    mutex m1, m2;

    {
        auto g1 = make_unique_lock(m1, adopt_lock);  //不执行锁定
        auto g2 = make_unique_lock(m2, adopt_lock);  //不执行锁定

        lock(m1, m2);  //锁定2个
    }

    {
        auto g1 = make_unique_lock(m1, defer_lock);  //不锁定
        auto g2 = make_unique_lock(m2, defer_lock);

        try_lock(g1, g2);  //尝试锁定
    }
}

#include <boost/thread/lockable_concepts.hpp>
void case6()
{
    BOOST_CONCEPT_ASSERT((BasicLockable<mutex>));
    BOOST_CONCEPT_ASSERT((Lockable<mutex>));

    BOOST_CONCEPT_ASSERT((Lockable<timed_mutex>));
    BOOST_CONCEPT_ASSERT((TimedLockable<timed_mutex>));

    BOOST_CONCEPT_ASSERT((Lockable<account>));
    BOOST_CONCEPT_ASSERT((Lockable<lockable_adapter<mutex>>));

    //BOOST_CONCEPT_ASSERT((Lockable<atomic<int>>));
}

//共享锁,读写锁
#include <boost/thread/shared_lock_guard.hpp>
class rw_data
{
    private:
        int m_x;
        shared_mutex rw_mu;
    public:
        rw_data():m_x(0){}
        void write()
        {
            unique_lock<shared_mutex> g(rw_mu);
            ++m_x;
        }
        
        //如果上面的锁没释放,下面的锁阻塞。
        //如果释放了,下面的读锁可以被很多人同时访问
        void read(int *x)
        {
            //shared_lock_guard<shared_mutex> g(rw_mu);
            shared_lock<shared_mutex> g(rw_mu);
            *x = m_x;
        }
};

void writer(rw_data &d)
{
    for (int i = 0;i < 20; ++i)
    {
        this_thread::sleep_for(3_ms);
        d.write();
    }
}

void reader(rw_data &d)
{
    int x;
    for (int i = 0;i < 4; ++i)
    {
        this_thread::sleep_for(5_ms);
        d.read(&x);
        cout << "reader:"<< x << endl;
    }
}

void case7()
{
    rw_data d;
    thread_group pool;

    pool.create_thread(bind(writer,boost::ref(d)));
    pool.create_thread(bind(writer,boost::ref(d)));

    pool.create_thread(bind(reader,boost::ref(d)));
    pool.create_thread(bind(reader,boost::ref(d)));
    pool.create_thread(bind(reader,boost::ref(d)));
    pool.create_thread(bind(reader,boost::ref(d)));

    pool.join_all();
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
}


 备注

1.编译器版本gcc4.8.5,运行环境centos7 64位
2.本文只做简单记录用,详细用法请参考 Boost Library,或者是罗剑锋的 boost程序库完全开发指南 书本
3..原文地址http://www.freecls.com/a/2712/b4


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。