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

前端 未结 8 1405
轮回少年
轮回少年 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:28

    Your problem is to associate the locking with the data. In my eyes, stuffing the mutex into the object is fine. You could go even further, making the objects essentially into monitors: Lock to enter a function member, unlock when leaving.

    0 讨论(0)
  • 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<Account> 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 <iostream>
    #include <utility>
    #include <ostream>
    #include <mutex>
    
    using namespace std;
    
    typedef int Money;
    
    struct Account
    {
        Money money = 1000;
        // ...
    };
    
    template<typename T>
    T &lvalue(T &&t)
    {
        return t;
    }
    
    template<typename T>
    class monitor
    {
        mutable mutex m;
        mutable T t;
    public:
        template<typename F>
        auto operator()(F f) const -> decltype(f(t))
        {
            return lock_guard<mutex>(m),
                   f(t);
        }
        template<typename F,typename ...Ts> friend
        auto transaction(F f,const monitor<Ts>& ...ms) ->
            decltype(f(ms.t ...))
        {
            return lock(lvalue(unique_lock<mutex>(ms.m,defer_lock))...),
            f(ms.t ...);
        }
    };
    
    int main()
    {
        monitor<Account> 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
    
    0 讨论(0)
提交回复
热议问题