/* SYNC-CLASSLOCK.hpp - special case of object based locking tied directly to a type Copyright (C) Lumiera.org 2008, Christian Thaeter Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file sync-classlock.hpp ** A special implementation of lib::Sync, where the storage of the object monitor ** is associated directly to a type rather then to a single object instance. While ** being problematic in conjunction with static startup/shutdown, doing so is sometimes ** necessary to setup type based dispatcher tables, managing singleton creation etc. ** ** @note simply using the ClassLock may cause a Monitor object (with a mutex) to be ** created at static initialisation and destroyed on application shutdown. ** @see singletonfactory.hpp usage example */ #ifndef LIB_SYNC_CLASSLOCK_H #define LIB_SYNC_CLASSLOCK_H #include "lib/nobug-init.hpp" #include "lib/sync.hpp" namespace lib { namespace nifty { // implementation details template struct Holder { static uint accessed_; static char content_[sizeof(X)]; Holder() { if (!accessed_) new(content_) X(); ++accessed_; } ~Holder() { --accessed_; if (0==accessed_) get().~X(); } X& get() { X* obj = reinterpret_cast (&content_); ASSERT (obj, "Logic of Schwartz counter broken."); return *obj; } }; template uint Holder::accessed_; template char Holder::content_[sizeof(X)]; } // (End) nifty implementation details /** * A synchronisation protection guard employing a lock scoped * to the parameter type as a whole, not an individual instance. * After creating an instance, every other access specifying the same * type is blocked. * @note the Lock is recursive, because several instances within the same * thread may want to acquire it at the same time without deadlock. * @note there is a design sloppiness, as two instantiations of the * ClassLock template with differing CONF count as different type. * Actually using two different configurations within for a single * class X should be detected and flagged as error, but actually * just two non-shared lock instances get created silently. Beware! * @see Sync::Lock the usual simple instance-bound variant */ template class ClassLock : public Sync::Lock { typedef typename Sync::Lock Lock; typedef typename sync::Monitor Monitor; struct PerClassMonitor : Monitor {}; Monitor& getPerClassMonitor() { static nifty::Holder __used_here; ASSERT (1==use_count(), "static init broken"); return __used_here.get(); } public: ClassLock(...) : Lock (getPerClassMonitor()) {} uint use_count() { return nifty::Holder::accessed_; } }; } // namespace lib #endif