#include "Mbo.h"
#include "MboDebugTrace.h"
#include <assert.h>
#include <vector>
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. |
Mutex
Lock
Event
Interlocked
incrementation/decrementationFor 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:
EventModel
MutexModel
LockSingle
LockMulti
Lock
IncDecVal
(Increment()
, Decrement()
, PeekValue()
)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 MBO_MEMBER_MUTEX_IMPL | ( | name, | |||
model | ) |
Value:
protected:\ model::CriticalSection m_mx ## name;\ virtual mbo::CLock GetLock() const { return mbo::CLock(&m_mx ## name); }
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 ![]() |