What's the proper way to associate a mutex with its data?

前端 未结 8 1413
轮回少年
轮回少年 2021-02-05 23:44

In the classic problem of transferring money from one bank account to another, the accepted solution (I believe) is to associate a mutex with each bank account, then lock both b

8条回答
  •  不知归路
    2021-02-06 00:35

    Check out Herb Sutter talk at C++ and Beyond 2012: C++ Concurrency. He shows example of Monitor Object-like implementation in C++11.

    monitor m[2];
    transaction([](Account &x,Account &y)
    {
        // Both accounts are automaticaly locked at this place.
        // Do whatever operations you want to do on them.
        x.money-=100;
        y.money+=100;
    },m[0],m[1]);
    // transaction - is variadic function template, it may accept many accounts
    

    Implementation:

    LIVE DEMO

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    typedef int Money;
    
    struct Account
    {
        Money money = 1000;
        // ...
    };
    
    template
    T &lvalue(T &&t)
    {
        return t;
    }
    
    template
    class monitor
    {
        mutable mutex m;
        mutable T t;
    public:
        template
        auto operator()(F f) const -> decltype(f(t))
        {
            return lock_guard(m),
                   f(t);
        }
        template friend
        auto transaction(F f,const monitor& ...ms) ->
            decltype(f(ms.t ...))
        {
            return lock(lvalue(unique_lock(ms.m,defer_lock))...),
            f(ms.t ...);
        }
    };
    
    int main()
    {
        monitor m[2];
    
        transaction([](Account &x,Account &y)
        {
            x.money-=100;
            y.money+=100;
        },m[0],m[1]);
    
        for(auto &&t : m)
            cout << t([](Account &x){return x.money;}) << endl;
    }
    

    Output is:

    900
    1100
    

提交回复
热议问题