Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat's the proper way to associate a mutex with its data?
    primarykey
    data
    text
    <p>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 before withdrawing the money from one account and depositing it into the other. At first blush, I'd do it like this:</p> <pre><code>class Account { public: void deposit(const Money&amp; amount); void withdraw(const Money&amp; amount); void lock() { m.lock(); } void unlock() { m.unlock(); } private: std::mutex m; }; void transfer(Account&amp; src, Account&amp; dest, const Money&amp; amount) { src.lock(); dest.lock(); src.withdraw(amount); dest.deposit(amount); dest.unlock(); src.unlock(); } </code></pre> <p>But the manual unlocking smells. I could make the mutex public, then use <code>std::lock_guard</code> in <code>transfer</code>, but public data members smell, too. </p> <p>The requirements for <code>std::lock_guard</code> are that its type satisfy the <em>BasicLockable</em> requirements, which is just that calls to <code>lock</code> and <code>unlock</code> are valid. <code>Account</code> satisfies that requirement, so I could just use <code>std::lock_guard</code> with <code>Account</code> directly:</p> <pre><code>void transfer(Account&amp; src, Account&amp; dest, const Money&amp; amount) { std::lock_guard&lt;Account&gt; g1(src); std::lock_guard&lt;Account&gt; g2(dest); src.withdraw(amount); dest.deposit(amount); } </code></pre> <p>This seems okay, but I've never seen this kind of thing done before, and duplicating the locking and unlocking of a mutex in <code>Account</code> seems kind of smelly in its own right.</p> <p>What's the best way to associate a mutex with the data it's protecting in a scenario like this?</p> <p>UPDATE: In comments below, I noted that <code>std::lock</code> can be used to avoid deadlock, but I overlooked that <code>std::lock</code> relies on the existence of <code>try_lock</code> functionality (in addition to that for <code>lock</code> and <code>unlock</code>). Adding <code>try_lock</code> to <code>Account</code>'s interface seems like a fairly gross hack. It thus seems that if the mutex for an <code>Account</code> object is to remain in <code>Account</code>, it has to be public. Which has quite the stench.</p> <p>Some proposed solutions have clients use wrapper classes to silently associate mutexes with an <code>Account</code> object, but, as I've noted in my comments, this seems to make it easy for different parts of the code to use different wrapper objects around <code>Account</code>, each creating its own mutex, and that means that different parts of the code may attempt to lock the <code>Account</code> using different mutexes. That's bad.</p> <p>Other proposed solutions rely on locking only a single mutex at a time. That eliminates the need to lock more than one mutex, but at the cost of making it possible for some threads to see inconsistent views of the system. In essence, this abandons transactional semantics for operations involving multiple objects. </p> <p>At this point, a public mutex is beginning to look like the least stinky of the available options, and that's a conclusion I really don't want to come to. Is there really nothing better?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload