From: jsiek_at_[hidden]
Date: 2000-06-05 17:49:51


My main complaint was the complexity of the atomic traits... but
if that is separate from the mutex, and if it can be made a bit
more generic, then I'll be OK with it.

As for the syntax of lock/unlock... well while we're being
cute, how about the following abuse of a for loop?

for (guard g(lock(m)); g; g.release()) {
  // critical section
}

This is pretty close to what John proposed... I've just added this
lock() function which solves the accidental default construction
problem, and used the "for" loop to create a convenient place to put
the g.release().

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

using namespace std;

struct mutex { };

namespace detail {
  struct guard_initializer { };
}

detail::guard_initializer lock(mutex) {
  cout << "lock" << endl;
  return detail::guard_initializer();
}

struct guard : boost::noncopyable {
  guard(detail::guard_initializer) : _locked(true) { }
  operator bool() { return _locked; }
  void release() {
    cout << "unlock via release" << endl;
    _locked = false;
  }
  ~guard() {
    if (_locked)
      cout << "unlock via destructor" << endl;
  }
  bool _locked;
};

mutex m;

int
main(int,char*[])
{
  try {
    cout << "before the critical section" << endl;
    for (guard g(lock(m)); g; g.release()) {
      cout << "in a critical section" << endl;
    }
    cout << "after first critical section" << endl;
    for (guard g(lock(m)); g; g.release()) {
      cout << "in another critical section" << endl;
      throw "foo";
    }
    cout << "after second critical section" << endl;
  } catch (...) {
    cout << "exception caught" << endl;
  }

  return 0;
}

This output is:

before the critical section
lock
in a critical section
unlock via release
after first critical section
lock
in another critical section
unlock via destructor
exception caught