MboSynch.h File Reference

Synchronization objects for multi threaded targets and their corresponding fakes for use in single threaded targets. This can also be used to implement class templates that can be instanciated with or without locking functionality. More...

#include "Mbo.h"
#include "MboDebugTrace.h"
#include <assert.h>
#include <vector>

Include dependency graph for MboSynch.h:

Mbo.hMboDebugTrace.hMboTString.harg_info.h

This graph shows which files directly or indirectly include this file:

MboThread.hMboIniData.hMboLockedVar.hMboRefCntPtr.hMboDrawWin.h

Go to the source code of this file.

Namespaces

namespace  mbo
namespace  mbo::MultiThreaded
namespace  mbo::SingleThreaded

Classes

class  mbo::ILock
 Lock interface. More...
class  mbo::IEvent
 Event implementation. More...
class  mbo::ICriticalSection
 Critical Section Interface. More...
class  mbo::IMutex
 Mutex Interface. More...
class  mbo::CLockFake
 Fake Lock implementation. More...
class  mbo::CLockSingle
 Single-Lock implementation. More...
class  mbo::CAlreadyEntered
 lock used with CPotentialLock More...
class  mbo::CPotentialLock
 Lock that might be entered. More...
class  mbo::CLock
class  mbo::CEventImpl
 Event implementation. More...
class  mbo::CEventFake
 Event emulation. More...
class  mbo::CCriticalSectionImpl
 Critical Section Implementation. More...
class  mbo::CCriticalSectionFake
 Critical Section Fake. More...
class  mbo::CMutexImpl
 Mutex implementation. More...
class  mbo::CMutexFake
 Mutex emulation. More...
class  mbo::MutexList
 MutexList implementation. More...
class  mbo::CLockMulti
 Multi-Lock implementation. More...
class  mbo::CUnlock
 Automatic local Lock unlock. More...
class  mbo::MultiThreaded::ThreadModel
 Class that defines types to be used in/for thread-safe environments. More...
class  mbo::SingleThreaded::ThreadModel
 Class that defines types to use in/for NON multithreaded environments. More...

Defines

#define MBO_MULTI_LOCK_SLEEPTIME   5
#define MBO_MEMBER_MUTEX_IMPL(name, model)

Typedefs

typedef LONG mbo::IncDecVal
typedef SingleThreaded::ThreadModel mbo::ThreadModel
typedef
ThreadModel::CriticalSection 
mbo::CriticalSection
typedef ThreadModel::EventModel mbo::EventModel
typedef ThreadModel::MutexModel mbo::MutexModel
typedef ThreadModel::LockSingle mbo::LockSingle
typedef ThreadModel::LockMulti mbo::LockMulti
typedef ThreadModel::Lock mbo::Lock
typedef ThreadModel::Unlock mbo::Unlock
typedef SingleThreaded::ThreadModel mbo::SingleThreadedModel
 Class that defines types to be used in/for thread-safe environments.
typedef MultiThreaded::ThreadModel mbo::MultiThreadedModel
 Class that defines types to be used in/for NON thread-safe environments.


Detailed Description

Synchronization objects for multi threaded targets and their corresponding fakes for use in single threaded targets. This can also be used to implement class templates that can be instanciated with or without locking functionality.

Author:
Marcus Boerger (http://marcus-boerger.de/)
Note:
This file is distributed under the LGPL license GNU Lesser General Public License, version 2.1.
This file defines the following synchronisation mechanismns:

For all these things there is an interface, an implemantation and an emulation. The interface is the type you should use in your code unless you want to force either the implementation or the emulation. Assuming you have chosen to use the interface you can use both interchangeable:

 
                                      |----------------|
                             ---------| implementation |
     |------------|          |        |----------------|
     | interface  |<---------|
     |------------|          |        |----------------|
                             ---------|   emulation    |
                                      |----------------|
 

All implementations are collected in the class ThreadModel in the namespace MultiThreaded and all emulations are collected in the class ThreadModel in the namespace SingleThreaded. The IDE controlled macro _MT imports one of the two ThreadModel classes and all the sub classes into this namespace. Doing this you can use the following types while the IDE automatically controlls whether or not thread safetiness has to be used:

Under windows the macro _MT specifies that the target will be multi threaded. This is used to correctly set typedef ThreadModel to default model (single/multi). Additionally import all symbols defined in the corresponding namespace into this namespace.

Mutex example:

  template<class ThreadModel>
  class Base
  {
  private:
     ThreadModel::MutexModel m_mx;
  public:
  
     virtual void Get()
     {
       m_mx.Enter();
       ....
       m_mx.Leave();
     }
  
     virtual void Set();
     {
       m_mx.Enter();
       ....
       m_mx.Leave();
     }
  };
  typedef Base<MultiThreadedModel>   ImplMT;
  typedef Base<SingleThreadedModel>  ImplST;
 

ImplMT really has a Mutex and calls Enter/Leave on that Mutex. In contrast ImplST has only a faked Mutex with same Interface. But better call it emulation instead of fake because this emulation lets do all the thinks you can do with real Mutex.

In the above example we have created two compareable class types that can be used interchangeable.

If you need to use instances of both classes interchangeable in containers you must simply implement a base class interface and make the template a derived class:

  class IBase
  {
    virtual void Get() =0;
    virtual void Set() =0;
  }
  
  template<class ThreadModel>
  class Base: public IBase
  { ...};
 
  template<class _Ty>
  class Container....
  { ... };
 
  class ImplST: public IBase<SingleThreadedModel>
  { ... };
 
  class ImplMT: public IBase<MultiThreadedModel>
  { ... };
 
  class BaseContainer: public Container<IBase>
  { ... };
 

In the above example we defined the template Container to hold any type and derived BaseContainer to hold IBase types. Therefore Base Container may store ImplST as well as ImplMT instances.

When using Synchronization objects one has to implement all necessary try catch blocks to have Leave been called in case of an exception and simple rethrow the exception.

Example from above:

  virtual void Get()
  {
    m_mx.Enter();
    try {
      ....
    }
    catch(...) {
      m_mx.Leave();
      throw;
    }
    m_mx.Leave();
  }
 

With Locks you simply do:

  virtual void Get()
  {
    ThreadModel::LockSingle lock(&m_mx);
    ....
    // as l_mxl is a local variable its destructor is called whether or 
    // not an exception is throwed. And therefore allways Leave will be
    // executed from within the Lock destructor.
  }
 

Since further more the mutex interface is able to return a lock you should prefer using this. Especially in derived classes if you hide the methods Enter(), Leave() using private inheritance or the private mutex member. Look in case like in the following example:

  class ImplST: private IBase<SingleThreadedModel>
  { ... 
  public:
    virtual void Get(); // increase visibility of inherited private method  
  };
 
  class Derived: public ImplST
  {
    // Even though ImplST is derived public we can only access GetLock() here
	// because the mutex is inherited private.

    virtual void Get()
	{
	  Lock  lock(GetLock());

	  ....
	}
  };
 

The interfaces mostly useses const function members which requires an implementation with mutable member variables. This is done because

When defining the macro MBO_MAX_MUTEX_TIME to a value greater zero the concrete mutex implementation CMutexImpl loggs all cases where the outmost Enter()/Leave() calls took longer then that amount of time in milliseconds.

To include MboSynch in your project you need the files Mbo.h, MboSynch.h and MboSynch.cpp. If you build a library you must specify MBO_API to either be __declspec(dllexport) for the library itself and __declspec(dllimport) for every library that uses MboSynch as an external library. In the case of libraries you also need to include the correct Windows headers.

Definition in file MboSynch.h.


Define Documentation

#define MBO_MEMBER_MUTEX_IMPL ( name,
model   ) 

Value:

protected:\
    model::CriticalSection  m_mx ## name;\
    virtual mbo::CLock  GetLock() const { return mbo::CLock(&m_mx ## name); }
Marco that implements the IMutex interface with the slightly different names. That is every method within IMutex is implemented with its name appended by the given name. Also a protected Mutex with the given name prepended by 'm_mx' will be created.

This macro is extremely usefull when building multiple inheritance and more than one base class has a Mutex or if you want to work with locks.

Example:

  template<class ThreadModel>
  class A
  {
    MBO_MEMBER_MUTEX_IMPL(A,ThreadModel) // -> member m_mxA
  };
  
  template<class ThreadModel>
  class B
  {
    MBO_MEMBER_MUTEX_IMPL(B,ThreadModel) // -> member m_mxB
  };
 

Since classes A and B use the macro MBO_MEMBER_MUTEX_IMPL you do have the following functions:

  template<class ThreadModel>
  class C: public A<ThreadModel>, public B<ThreadModel>, pblic IMutex
  {
  public:
  
    virtual void Action()
    {
      Enter();
      try {
        ...
      }
      catch(...) {
        Leave();
        throw;
      }
      Leave()
    }
    
  protected:
  
    virtual void Try()
    {
      return ThreadModel::LockMulti::Try(NULL, 2, &m_mxA, &m_mxB);
    }
    
    virtual void Leave()
    {
      ThreadModel::LockMulti::Leave(NULL, 2, &m_mxA, &m_mxB);
    }
  };
 

You do not have to implement Enter() from IMutex for class C because that function uses Try by default.

You can simplify local mutual exclusion by using CLock:

  class D: public C
  {
  public:
  
    virtual void Action()
    {
      ThreadModel::CLock lock(GetLock());
      ...
    }
    
    virtual void Action2()
    {
      ThreadModel::CLock lock(ThreadModel::CMultiLock(&m_mxA, &m_mxB);
      ...
    }
    
  protected:
  
    virtual CLock GetLock() const
    {
      return ThreadModel::CLockMulti(&m_mxA, &m_mxB);
    }
  };
 

In the above example it is important that GetLock returns a CLock instance by copy. Because first you cannot return a local address inside a member function and second but more important otherwise Enter/Leave would be incorrectly used on m_mxA and m_mxB.

Further more it is of no importance whether the CLock instance is created by an already Entered ILock or not. Therefore you do not have to call the functions Enter() and Leave() manually yourself.

Definition at line 1578 of file MboSynch.h.

#define MBO_MULTI_LOCK_SLEEPTIME   5

Definition at line 242 of file MboSynch.h.


  Hosted on code.google.com  
© Marcus Börger
Generated on Fri Jan 18 21:21:08 2008 for MBO-lib by doxygen 1.5.4