Tuesday, May 18, 2010

Exception-based Timed Locks

A notable feature of Boost.Synchro is the use of exceptions in conjunction with timed locks. This extension is based on the idea of Kevlin Henney presented on "More C++ Threading".
In addition to the standard try_lock_until/try_lock_for which returns false on expiry, Boost.Synchro adds two functions lock_until and lock_for which lock until a specified time is reached or a specified amount of time is elapsed, respectively, and throw a timeout exception on expiry.

The implementation of these function is of course quite simple. Just wrapping the try_clock_... call and throw the exception when  try_clock_... return false.

template<typename Clock, typename Duration>
void lock_until(chrono::time_point<Clock, Duration> const & abs_time)
{
  if(!try_lock_until(abs_time)) 
    throw timeout_exception();
}
template<typename Rep, typename Period>
void lock_for(chrono::duration<Rep, Period> const & rel_time)
{
  if(!try_lock_for(rel_time)) 
    throw timeout_exception();
}

Exception-based Timed Lockers
In addition to supporting timeout exception for Lockables, the library supports them also for exception-based timed lockers. The semantics of each constructor and member function are identical to those of boost::unique_lock for the same Lockable, except that the constructor that takes a time or a duration as first parameter in addition to the reference to a mutex will call m.lock_until(t) or m.lock_for(d) rather than m.try_lock_until(t) or m.try_lock_for(d) and so a timeout_exception is possible on the constructor.

Let me start with an example of an application needing to lock several locks at the same time. Once all the locks are locked something must be done. Otherwise the application do something else and reiterate the lock requests. The natural and exception safe way to do that is

while (polling) {
  t=now()+100;
  std::unique_lock<boost::mutex> l1(m1, t);
  std::unique_lock<boost::mutex> l2(m2, t);
  std::unique_lock<boost::mutex> l3(m3, t);
  if (l1.has_lock() && l2.has_lock() && l3.has_lock()) {
    foo();
    polling = false;
  } else execute_on_failed();
}

The problem with this code is that it locks m2 even if l1 do not owns the lock m1. The advertised reader could argument that if the lock m1 has not been locked by a timeout, as all share the same time constraint the failing lock of m2 will not be expensive. Well the problem is that the locking of m1 can fail because m1 is already locked. When we try to optimize this

while (polling) {
  t=now()+100;
  boost::unique_lock<boost::mutex> l1(m1, t);
  if (l1.has_lock()) {
    boost::unique_lock<boost::mutex> l2(m2, t);
    if (l2.has_lock()) {
      boost::unique_lock<mutex> l3(m3, t);
      if (l2.has_lock()) {
        foo();
        polling = false;
      } else execute_on_failed();
    } else execute_on_failed();
  } else execute_on_failed();
}

the code becomes unmaintainable. What is event worst is that as the preceding one is subject to deadlock if another thread acquire the locks in a different order.

try_lock_until and try_lock_for non-member functions
To avoid this we can request the acquisition of all the locks together (letting the function to try several orders), as it does the function std::try_lock, but adding this time a expiration period parameter

while (polling) {
  if (bsynchro::try_lock_for(100, m1, m2, m3)) {
    foo();
    polling = false; 
    bsynchro::unlock(m1, m2, m3)
  } else execute_on_failed();
}
While this solve the deadlock problem, this code is not exception safe.
We can improve this  code using the standard unique_lock, but deferring the lock as follows:

while (polling) {
  t=now()+100;
  std::unique_lock<boost::mutex> l1(m1, defer_lock);
  std::unique_lock<boost::mutex> l2(m2, defer_lock);
  std::unique_lock<boost::mutex> l3(m3, defer_lock);
  bsynchro::try_lock_until(now()+100, l1, l2, l3);
  if (l1.has_lock()) {
    foo();
    polling = false;
  } else execute_on_failed();
}
Note that we need just to check for one of the lock as either all the locks are locked on none.

With exception based lockers we can do the following (note that the time is given as first argument to the locker constructor)
while (polling) try {
  bsynchro::unique_locker<boost::mutex> l1(t, m1);
  bsynchro::unique_locker<boost::mutex> l2(t, m2);
  bsynchro::unique_locker<boost::mutex> l3(t, m3);
  foo();
  polling = false;
} catch (bsynchro::timeout_exception& ex) {
  execute_on_failed();
} 
While the preceding code is exception safe and do not locks m2 if m1 is not acquired, do not avoid the deadlock when another thread  takes m1, m2 and m3 on a different order.

lock_until and lock_for non-member functions

We can yet try with

while (polling) try {
  std::unique_lock<boost::mutex> l1(m1, defer_lock);
  std::unique_lock<boost::mutex> l2(m2, defer_lock);
  std::unique_lock<boost::mutex> l3(m3, defer_lock);
  bsynchro::lock_until(now()+100, l1, l2, l3);
  foo();
  polling = false;
} catch (bsynchro::timeout_exception& ex) {
  execute_on_failed();
}


locker_tuples or locker_array of Locker
We can go a step ahead and mix the advantage of taking all the locks at once and making the acquisition block scoped. In order to do that we need either a array_locker or a tuple_locker depending on whether the locks are homogeneous or not. These locker containers follows the same rules as the element wise lockers. If the time comes after the locks no exception is thrown on timeout and if given as the first parameter a exception will be thrown when the time will expire.
Using array_unique_locker the preceding code becomes without timeout exceptions
while (polling) {
  bsynchro::array_unique_locker<boost::mutex, 3> lk(m1, m2, m3, 100);
  if (lk.owns_lock()) {
    foo();
    polling = false;
  } else execute_on_failed();
}
which is exception safe, efficient and help to avoid deadlocks.
With exception based timed locks (Note that the time is given before the locks)
while (polling) try {
  bsynchro::array_locker<boost::mutex, 3> lk(100, m1, m2, m3);
  foo();
  polling = false;
} catch (bsynchro::timeout_exception& ex) {
  execute_on_failed();
} 

Friday, May 7, 2010

Language-like Synchronized Block

In "A 'synchronized' statement for C++ like in Java" Achilleas Margaritis presents a synchronized macro that emulates the Java behavior.
  synchronized(l) {
    foo();
    return bar();
  } 
I have adapted the macro to use Boost.Thread as follows:
#define synchronized(MUTEX) \
  if (bool _stop_ = false) {} else \
  for (boost::scoped_guard<boost::mutex> _lock_(MUTEX); 
      !_stop_; _stop_ = true)
How it works?
The macro exploits the nature of the if and for statements of C++ to do the following (in the presented order):
  1. The if condition introduces a new _stop_ variable on the scope of if statement, which is the initialized to false, so the else part will be executed.
  2. for initialization part: a local _lock_ variable is defined that locks the given mutex.
  3. test part: the !_stop_ expression is found to be true: the code inside the loop is executed.
  4. increment part: the _stop_ variable is set to true.
  5. test part: the !_stop_ expression is found to be false: the loop exits.
  6. exit part: the _lock_ variable is destroyed, unlocking the mutex.
The advantage over the initial proposal:
  • no need to wrap a locker class to add extra functions to set the flag neither a conversion operator to bool.
Advantages over classic RAI:
  • it makes the code more language-like, pretending synchronized to be a keyword,
  • it helps avoiding declaration of the auxiliary lock variable, and
  • it ties the code to be synchronized with the next statement either simple or compound.
For example no need to add curly brackets to synchronize a sentence as in
  {
    boost::scoped_guard<boost::mutex> _lock_(l);
    ++cnt;
  }
Just prefix the sentence with
  synchronized(l) ++cnt;

With exception-based timed locks we can define synchronized_until and synchronized_for. Both can throw a timeout_exception
  synchronized_until(l,abs) ++cnt;

Saturday, May 1, 2010

Shallow-Copy Semantics

I have read in too many places this sentence

"The default copy constructor and assignment operator make shallow copies"

This is not completely right. I would say, the generated copy constructor and assignment operator make default copies of the direct class members, and calls to the copy constructor or assignment operator of the base classes. If the member or base classes define the default copy constructor and assignment operator with deep copy semantics, the generated defaults will have a mix of both copy semantics.

This means that we can not let the compiler generate a shallow copy for us if the class has members or inherits in a general case.

Applications needing shallow copy semantics must follow a strict protocol. Here I present an explicit approach. Classes providing shallow copy semantics must define at least a default shallow copy constructor and a shallow assignment function.

The default copy constructor and assignment for the C++ fundamental and pointers types has shallow copy semantics. For the other compound types we need to make the difference between shallow copy and deep copy. We can use a tag for this purpose.

struct shallow_t {};
const shallow_t shallow = {};
C(shallow_t, C const&);
C& shallow_assign(C const&);

For base classes we need to take care just of members.

struct B {
  C c;
  B(shallow_t, B const& rhs) 
    : c(shallow, rhs.c) {}
  B& shallow_assign(B const& rhs){
    if (this!=&rhs) {
      c.shallow_assign(rhs.c);
    }
    return *this;
  }
};

For derived classes we do like:
struct D : B {
  D(shallow_t, D const& d) : B(shallow, d)
  // shallow copy construct the fields
  {
  }
  D& shallow_assign(D const& rhs){
    if (this!=&rhs) {
      this->B::shallow_assign(rhs);
      // shallow copy the fields
    }
    return *this;
  }
};

Now we are able to shallow copy objects as far as we follows the protocol.

D d1; 
D D2(shallow, D2);
D d3;
d3.shallow_assign(d1);

The main problem while trying to integrate shallow copy semantic in C++ is that we can not have function parameters or return types shallow copied as C++ call the copy constructor instead. For function parameters we should pass them by reference and call the shallow copy inside the function when needed.


Saturday, April 24, 2010

private_ptr: A friend smart pointer to access private members

Friend can be used to access the internals of a class for unitary test purposes. We can define an smart pointer private_ptr template class and a private_cast template function, which gives a private access to a class in the same way const_cast grant non const access.
// private_ptr.h
template <typename Concept> 
class private_ptr {
  private_ptr(Concept & c) : c_(c) {}
  Concept * operator->() {
    return &c_;
  }
  const Concept* operator->() const {
    return &c_;
  }
};
template <typename Concept> 
private_ptr> private_cast(Concept& c) {
    return private_ptr(c);
}
A class can grant friend access to the private pointer class in a controlled way,  e.g. unit tests access to the private members,  as follows:

#include <private_ptr.hpp>
class C {
#ifdef C_UNIT_TEST
    friend class private_ptr<C>;
#endif
    // ...
};
As the friend class is defined only if C_UNIT_TEST is defined, there is no risk that application code uses this back-door access. The unit test code can access private members as follows:

#include <C.hpp>
void test_private()
{
  // ...
  C c;
  private_cast(c)->private_op();
  assert(private_cast(c)->private_field==0);
  //...
}

Unfortunately this smart pointer can not be used to access private types.

Monday, April 19, 2010

Extrinsic Conversions

I've needed recently to convert from chrono::time_point to posix_time::ptime and from chrono::duration to posix_time::time_duration.
This kind of conversions are needed quite often when you use code from two different libraries that have implemented the same concept using of course different representations and have hard coded the library interface to its own implementation. Well this is a normal situation we can't avoid. Life is life.
Quite often we need to convert unrelated types Source and Target. As these classes are unrelated, neither of them offers conversion operators to the other. Usually we get it by defining a specific function such as
Target ConvertToTarget(Source& v);
In my case I started by defining
template <typename Rep, typename Period>
boost::posix_time::time_duration
convert_to_posix_time_time_duration(
  const boost::chrono::duration<Rep, Period>& from);

template <typename Clock, typename Duration>
posix_time::ptime
convert_to_posix_time_ptime(
  const chrono::time_point<Clock, Duration>& from);
Imagine now that you need to convert a std::pair<Source, Source> to a std::pair<Target, Target>. The standard defines conversions of pairs if the related types are C++ convertible:
template <typename T1, typename T2>
struct pair {
  ...
  template<class U, class V>
  //requires Constructible 
  // && Constructible
  std::pair(const pair<U, V>& p);

  template<class U , class V>
  //requires HasAssign 
  // && HasAssign
  std::pair& operator=(const std::pair<U , V>& p);
  ...
};
But as the types Target and Source are not C++ convertible other than using a specific function.
Well we can again define a specific function
std::pair<Target,Target>
ConvertToPairOfTarget(std::pair<Source,Source>& v)
{
  return std::make_pair(
  ConvertToTarget(v.fisrt),
  ConvertToTarget(v.second));
}
While the ConvertToTarget could be specific, the ConvertToPairOfTarget should be generic
template <typename Target1, typename Target2
, typename Source1, typename Source2>
std::pair<Target1,Target2>
ConvertToPair(std::pair<Source1,Source2>& v);

In order to do that we need that the pair template parameters define a common function, let it call convert_to
template <typename Target, typename Source>
Target convert_to(Source& v);
so ConvertToPair can be defined as

template <typename Target1, typename Target2,
typename Source1, typename Source2>
std::pair<Target1,Target2>
ConvertToPair(std::pair<Source1,Source2>& v)
{
  return std::make_pair(
  convert_to<Target1>(v.fisrt),
  convert_to<Target2>(v.second));
}
We need to specialize the convert_to function for the specific classes Source and Target. We can do it as follows
Target  convert_to(Source& v) {
  return ConvertToTarget(v);
}
So now I can convert std::pair<chrono::time_point<Clock, Duration>, boost::chrono::duration<Rep, Period> > to std::pair<boost::posix_time::ptime, boost::posix_time::time_duration> using the ConvertToPair function.
What about converting std::pair<Source,std::pair<Source,Source> > to std::pair<Target,std::pair<Target,Target> >? The issue now is that convert_to(std::make_pair<to, std::make_pair<to,to> >) do not compiles because the conversion of std::pair is named ConvertToPair. So we need to specialize the function convert_to for pairs.
template <typename T1, typename T2,
typename S1, typename S2>
static std::pair<T1,T2>
convert_to(std::pair<Source1,Source2>& from) {
{
  return std::pair<T1,T2>(
  convert_to<T1>(from.first),
  convert_to<T2>(from.second));
}
There is still a last point. The preceding design works well with unrelated classes, but what about classes that already define some kind of conversion, using a constructor or a conversion operator. Do we need to make specialization for these conversion? The answer is no. We need just to define the default implementation of convert_to function to just return the explicit conversion.
template < typename Target, typename Source>
Target convert_to(const Source& from)
{
  return Target(from);
}
Classes or algorithms relying on a conversion by copy-construction or by the conversion operator can be made more generic by relaying in a function that explicitly states this conversion. Thus, instead of requiring
Target(from)
requires
convert_to<Target>(from)
So one of the advantages of using this common functions is uniformity. The other is that now we are able to find all the explicit conversions to one type, as we can do with explicit casts.

C++ Evolution?
C++0x has added explicit conversion operators, but they must always be defined in the Source class. The same applies to the assignment operator, it must be defined on the Target class.
What it will interesting is to be able to add constructors and assignments operators to the class std::pair, so we can say that two pairs are convertible if the parameters are explicitly convertible using a convert_to function
template<class U , class V>
  //requires HasConvertTo 
  // && HasConvertTo
  std::pair& operator=(const std::pair<U , V>& p) {
  return std::make_pair(
  convert_to<T1>(p.first),
  convert_to<T2>(p.second));
}
But this is not currently possible, we can not add operations to a class.

Another possibility could be to make an evolution to the C++ standard, so the convertible concept takes care of extrinsic conversions. We could be able to implicitly or explicitly add extrinsic conversion operators between unrelated types.
template < typename To, typename From >
operator To(const From& val);
For example we could specialize the conversion from chrono::time_point to posix_time::ptime as follows
template < class Clock, class Duration>
operator boost::posix_time::ptime(
const boost::chrono::time_point<Clock, Duration>& from)
{
  using namespace boost;
  typedef chrono::time_point<Clock, Duration> time_point_t;
  typedef chrono::nanoseconds duration_t;
  typedef duration_t::rep rep_t;
  rep_t d = chrono::duration_cast<duration_t>(
  from.time_since_epoch()).count();
  rep_t sec = d/1000000000;
  rep_t nsec = d%1000000000;
  return  posix_time::from_time_t(0)+
    posix_time::seconds(static_cast<long>(sec))+
    posix_time::nanoseconds(nsec);
}

Tuesday, April 13, 2010

Backdoor C++ Idiom - part III

I will end this suite around the backdoor C++ idiom with implementation variants.

Implementation

Analyze applicability
First of all, the designer must be sure the pattern is applicable to the class by checking the applicability clauses.

Identify the part of the Component that must be used with caution and its protocol
This is a class specific task that must be done with caution. Only the actual safe operations must be public. Operations and data which are needed to open the interface and which must be used with caution by a safe adapter class should be private and usually annotated as such.
class  mutex {
public:
  // ... 
  typedef mutex_backdoor backdoor;
  friend class backdoor ;
  // list of predefined safe adapters
  typedef mutex_scoped_lock scoped_lock;
private: // backdoor 
  void  lock();// backdoor 
  void  unlock();// backdoor 
  // ... 
};
If the Component is a model of a Concept, which has already a backdoor through a template class and safe component adapters, use them.
class  mutex {
public:
  // ... 
  typedef backdoor<mutex> backdoor;
  friend class backdoor ;
  typedef scoped_lock<mutex> scoped_lock;
  // ... 
};
Safe guaranties: unlock must be called if lock is called, i.e. lock/unlock are well balanced.

Define a backdoor interface and safe guaranties for Component

This class gives you a back-door access to your class. There are at least two possibilities: by class instance or static
  • instance interface: an instance of a backdoor is initialized with an instance of the class, giving back-door access


  • static interface: this could be more efficient with compilers that haven't a good optimizer.
Instance interface
class  mutex_backdoor {
public:
  mutex_backdoor ( mutex & mtx) : mtx_(mtx) {}
  void lock() {
    mtx_.lock();
  }
  void unlock() {
    mtx_.unlock();
  }
private:
  mutex & mtx_;
};
The SafeAdapter client could write
mutex::backdoor(mtx).lock();

Static interface
struct mutex_backdoor {
  static void lock(mutex& mtx) {
    mtx.lock();
  }
  static void unlock(mutex& mtx) {
    mtx.unlock();
  }
};
The SafeAdapter client could write
mutex_backdoor::lock(mtx); 
 
When applying the idiom to generic programming, the backdoor should be applied to a concept. So, the backdoor for a mutex class can be a template class, which is the backdoor for models of the Lockable concept, and then the backdoor is written only once. For brevity purposes only the by instance class interface is shown:
template <typename Lockable>
class  backdoor {
  backdoor( Lockable & mtx) : mtx_(mtx) {}
  void lock() {
    mtx_.lock();
  }
  void unlock() {
    mtx_.unlock();
  }
private:
  Lockable& mtx_;
};
And the SafeAdapter client could write
backdoor<mutex>(mtx).lock();

The use of the backdoor template class can be simplified by using a backdoor generator function:
template <typename Lockable>
typename Lockable::backdoor backdoor_access( Lockable& mtx)
{
  return Lockable:: backdoor(mtx);
}
And the SafeAdapter client could write
backdoor_access(mtx).lock();

Define a set of Component Safe Adapters that provides a safe interface to your Component

This set of ComponentSafeAdapters must at least provide the same functionalities as the Component would provide if the interface of the backdoor were public in a safe way. For brevity purposes, only the generic safe component adapter accessing a per instance backdoor is shown:
 
// ensures that unlock is called on destruction when owned 
// note that this is different to ensure that the mutex is 
// locked during the lifetime of the scoped variable. 
template <typename Lockable>
class  scoped_lock {
public :
  scoped_lock( Lockable & mtx, bool owns=true) // [1] 
    : mtx_(mtx),
    , owned(false) {
    if (owns) lock();// [2] 
  }
  ~scoped_lock(mutex&) {
    if (owned) { // [5] 
      backdoor_access(mtx_).unlock();// [4] 
    }
  }
  void  lock() {
    if (!owned) { // [3] 
      backdoor_access(mtx_).lock();// [4] 
      owned = true; // [3] 
    } else {
      // ERROR // [6] 
    }
  }
  void  unlock() {
    if (owned) { // [3] 
      backdoor_access(mtx_).unlock();// [4] 
      owned = false; // [3] 
    } else {
      // ERROR // [6] 
    } 
  } 
 bool  owned() {
    return owned;
  }
private :
  bool owned;
  mutex& mtx_;
};
  1. The interface allows to lock the mutex on construction
  2. Use of an internal function
  3. The use of the lock/unlock is controlled by the owned variable
  4. Use of backdoor interface using the backdoor_access function.
  5. On destruction the mutex is unlocked if owned.
  6. Error has not been detailed.
Use the component and the Component Safe Adapters
The use of the ComponentSafeAdapter is obvious.
 
mutex guard;
{
  // guard.lock() compilation ERROR
  mutex::scoped_lock scoped( guard );
  // enter the critical section
  // ...
  // guard.unlock() compilation ERROR
}

Identify other Component Safe Adapters

Different Component Safe Adapters can be identified. Associated to the Lockable concept there are:
  • scoped_strict_lock: ensures that the mutex is owned during the lifetime of the scoped variable.
  • locking_ptr: this smart pointer locks the mutex when de-referencing the pointer, call the function, and then unlocks the mutex.
  • scoped_locking_ptr: this smart pointer locks the mutex on construction, defines the operator->, and unlocks the mutex on destruction.
  • scoped_reverse_lock: unlocks the mutex on construction, and locks the mutex on destruction. For recursive mutex, this do not implies that on the scoped block the mutex is unlocked.
The designer of such ComponentSafeAdapter must be aware of the possible interactions between the set of adapters, and must specify which are the guaranties. Next follows some interactions between ComponentSafeAdapters.
mutex guard;
void f()
{
  scoped_strict_lock strict( guard );
  // the mutex is locked 
  {
    // call to a self locked function 
    // this will work if the mutex is recursive 
    g();
    // pass a strict lock to a function. The “other” object has been 
    // constructed with an external locking mechanism and its correct 
    // behavior depends on the caller, which owns the mutex. 
    // Having a strict lock ensures this. 
    other.h(strict);
  }
  {
    // the user is aware that on this block the mutex must be unlocked but a strict guards is not a scoped_lock 
    scoped_reverse_lock reverse( strict ); // ERROR do not compile 
    // the mutex is unlocked 
    // ... 
    // the mutex is locked  
  }
  // the mutex is still locked 
  h( strict );
}
void g() {
scoped_lock scoped( guard );
  // mutex is locked 
  // ... 
  {
    scoped_reverse_lock reverse( scoped );
    // the mutex is unlocked 
    // ... 
    // the mutex is locked 
  }
  // mutex is locked 
  // ... 
} 
 
Know Uses
  • Boost::Threads library (v1. 34.1): The synchronization part of this library used the backdoor for the model of the Lockable concept with a static interface (lock_ops) defined on a nested namespace named ‘detail'. It is admitted that the ‘detail' namespace is private namespace and do not make part of the interface. The backdoor class specified more explicitly which is the intent of this kind of classes.
Related Patterns
  • RAII (Resource Initialization Is Initialization): The component safe adapters usually use the RAII idiom in order to reach on destruction a stable state for the Component.
  • Extension object: The ComponentSafeAdapter can be seen as an Extension objects of the Component.