// -*- c++ -*- // Generated by gtkmmproc -- DO NOT MODIFY! #ifndef _GLIBMM_THREAD_H #define _GLIBMM_THREAD_H /* $Id$ */ /* Copyright (C) 2002 The gtkmm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include /* Shadow THREAD_PRIORITY_NORMAL macro (from winbase.h). */ #if defined(THREAD_PRIORITY_NORMAL) && !defined(GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL) enum { GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL = THREAD_PRIORITY_NORMAL }; #undef THREAD_PRIORITY_NORMAL enum { THREAD_PRIORITY_NORMAL = GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL }; #define THREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL #define GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL 1 #endif /** Initializer macro for Glib::StaticMutex. * @relates Glib::StaticMutex * @hideinitializer */ #define GLIBMM_STATIC_MUTEX_INIT { G_STATIC_MUTEX_INIT } /** Initializer macro for Glib::StaticRecMutex. * @relates Glib::StaticRecMutex * @hideinitializer */ #define GLIBMM_STATIC_REC_MUTEX_INIT { G_STATIC_REC_MUTEX_INIT } /** Initializer macro for Glib::StaticRWLock. * @relates Glib::StaticRWLock * @hideinitializer */ #define GLIBMM_STATIC_RW_LOCK_INIT { G_STATIC_RW_LOCK_INIT } /** Initializer macro for Glib::StaticPrivate. * @relates Glib::StaticPrivate * @hideinitializer */ #define GLIBMM_STATIC_PRIVATE_INIT { G_STATIC_PRIVATE_INIT } namespace Glib { /** @addtogroup glibmmEnums Enums and Flags */ /** Specifies the priority of a thread. * @note It is not guaranteed, that threads with different priorities really * behave accordingly. On some systems (e.g. Linux) only root can * increase priorities. On other systems (e.g. Solaris) there doesn't seem to * be different scheduling for different priorities. All in all try to avoid * being dependent on priorities. * @ingroup glibmmEnums */ enum ThreadPriority { THREAD_PRIORITY_LOW, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGH, THREAD_PRIORITY_URGENT }; /*! @var ThreadPriority THREAD_PRIORITY_LOW * A priority lower than normal. */ /*! @var ThreadPriority THREAD_PRIORITY_NORMAL * The default priority. */ /*! @var ThreadPriority THREAD_PRIORITY_HIGH * A priority higher than normal. */ /*! @var ThreadPriority THREAD_PRIORITY_URGENT * The highest priority. */ /** @defgroup Threads Threads * Thread abstraction; including threads, different mutexes, * conditions and thread private data. * @{ */ enum NotLock { NOT_LOCK }; enum TryLock { TRY_LOCK }; /** Initializes the GLib thread system. * Before you use a thread related function in glibmm, you should initialize * the thread system. This is done by calling Glib::thread_init(). * * @note You should only call thread_init() with a non-0 parameter * if you really know what you are doing. * * @note thread_init() must not be called directly or indirectly as * a callback from glibmm. Also no mutexes may be currently locked while * calling thread_init(). * * thread_init() might only be called once. On the second call it will * abort with an error. If you want to make sure that the thread system * is initialized, you can do that too: * @code * if(!Glib::thread_supported()) Glib::thread_init(); * @endcode * After that line either the thread system is initialized, or the program * will abort if no thread system is available in GLib, i.e. either * @c G_THREADS_ENABLED is not defined or @c G_THREADS_IMPL_NONE is defined. * * If no thread system is available and @a vtable is 0 or if not all * elements of @a vtable are non-0, then thread_init() will abort. * * @note To use thread_init() in your program, you have to link with the * libraries that the command pkg-config --libs gthread-2.0 * outputs. This is not the case for all the other thread related functions * of glibmm. Those can be used without having to link with the thread * libraries. (You @em have to link with gthread-2.0 if you actually * want to use threads in your application, though.) * * @param vtable A function table of type @c GThreadFunctions, that provides * the entry points to the thread system to be used. */ inline void thread_init(GThreadFunctions* vtable = 0); /** Returns whether the thread system is initialized. * @return @c true, if the thread system is initialized. */ inline bool thread_supported(); class Mutex; class RecMutex; class RWLock; struct StaticMutex; struct StaticRecMutex; struct StaticRWLock; /** Exception class for thread-related errors. */ class ThreadError : public Glib::Error { public: enum Code { AGAIN }; ThreadError(Code error_code, const Glib::ustring& error_message); explicit ThreadError(GError* gobject); Code code() const; #ifndef DOXYGEN_SHOULD_SKIP_THIS private: static void throw_func(GError* gobject); friend void wrap_init(); // uses throw_func() #endif }; /** Represents a running thread. * An instance of this class can only be obtained with create(), self(), * or wrap(GThread*). It's not possible to delete a Thread object. If the * thread is @em not joinable, its resources will be freed automatically * when it exits. Otherwise, if the thread @em is joinable, you must call * join() to avoid a memory leak. * * @note g_thread_exit() is not wrapped, because that function exits a thread * without any cleanup. That's especially dangerous in C++ code, since the * destructors of automatic objects won't be invoked. Instead, you can throw * a Thread::Exit exception, which will be caught by the internal thread * entry function. * * @note You might have noticed that the thread entry slot doesn't have the * usual void* return value. If you want to return any data from your thread * you can pass an additional output argument to the thread's entry slot. */ class Thread { public: class Exit; /** Creates a new thread with the priority THREAD_PRIORITY_NORMAL. * If @a joinable is @c true, you can wait for this thread's termination by * calling join(). Otherwise the thread will just disappear, when ready. * * The new thread executes the function or method @a slot points to. You can * pass additional arguments using sigc::bind(). If the thread was created * successfully, it is returned, otherwise a ThreadError exception is thrown. * * @param slot A slot to execute in the new thread. * @param joinable Should this thread be joinable? * @return The new Thread* on success. * @throw Glib::ThreadError */ static Thread* create(const sigc::slot& slot, bool joinable); /** Creates a new thread with the priority @a priority. The stack gets the * size @a stack_size or the default value for the current platform, if * @a stack_size is 0. * * If @a joinable is @c true, you can wait for this thread's termination by * calling join(). Otherwise the thread will just disappear, when ready. * If @a bound is @c true, this thread will be scheduled in the system scope, * otherwise the implementation is free to do scheduling in the process * scope. The first variant is more expensive resource-wise, but generally * faster. On some systems (e.g. Linux) all threads are bound. * * The new thread executes the function or method @a slot points to. You can * pass additional arguments using sigc::bind(). If the thread was created * successfully, it is returned. * * @note It is not guaranteed, that threads with different priorities really * behave accordingly. On some systems (e.g. Linux) only root can increase * priorities. On other systems (e.g. Solaris) there doesn't seem to be * different scheduling for different priorities. All in all try to avoid * being dependent on priorities. Use Glib::THREAD_PRIORITY_NORMAL * here as a default. * * @note Only use the extended * create(const sigc::slot&, unsigned long, bool, bool, ThreadPriority) * function, when you really can't use the simple * create(const sigc::slot&, bool) * instead. The latter overload does not take @a stack_size, @a bound and * @a priority as arguments, as they should only be used for cases, where * it is inevitable. * * @param slot A slot to execute in the new thread. * @param stack_size A stack size for the new thread, or 0. * @param joinable Should this thread be joinable? * @param bound Should this thread be bound to a system thread? * @param priority A priority for the thread. * @return The new Thread* on success. * @throw Glib::ThreadError */ static Thread* create(const sigc::slot& slot, unsigned long stack_size, bool joinable, bool bound, ThreadPriority priority); /** Returns the Thread* corresponding to the calling thread. * @return The current thread. */ static Thread* self(); /** Returns whether the thread is joinable. * @return Whether the thread is joinable. */ bool joinable() const; /** Waits until the thread finishes. * Waits until the thread finishes, i.e. the slot, as given to create(), * returns or g_thread_exit() is called by the thread. (Calling * g_thread_exit() in a C++ program should be avoided.) All resources of * the thread including the Glib::Thread object are released. The thread * must have been created with joinable = true. */ void join(); /** Changes the priority of the thread to @a priority. * @note It is not guaranteed, that threads with different priorities really * behave accordingly. On some systems (e.g. Linux) only @c root can * increase priorities. On other systems (e.g. Solaris) there doesn't seem * to be different scheduling for different priorities. All in all try to * avoid being dependent on priorities. * @param priority A new priority for the thread. */ void set_priority(ThreadPriority priority); /** Returns the priority of the thread. * @return The thread's priority. */ ThreadPriority get_priority() const; /** Gives way to other threads waiting to be scheduled. * This function is often used as a method to make busy wait less evil. But * in most cases, you will encounter, there are better methods to do that. * So in general you shouldn't use this function. */ static void yield(); GThread* gobj() { return &gobject_; } const GThread* gobj() const { return &gobject_; } private: GThread gobject_; // Glib::Thread can neither be constructed nor deleted. Thread(); void operator delete(void*, size_t); // noncopyable Thread(const Thread&); Thread& operator=(const Thread&); }; /** %Exception class used to exit from a thread. * @code * throw Glib::Thread::Exit(); * @endcode * Write this if you want to exit from a thread created by Thread::create(). * Of course you must make sure not to catch Thread::Exit by accident, i.e. * when using catch(...) somewhere in your code. */ class Thread::Exit {}; /** @relates Glib::Thread */ Thread* wrap(GThread* gobject); /** Like Glib::Mutex, but can be defined at compile time. * Use @c GLIBMM_STATIC_MUTEX_INIT to initialize a StaticMutex: * @code * Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT; * @endcode * A StaticMutex can be used without calling Glib::thread_init(), it will * silently do nothing then. That will also work when using the implicit * conversion to Mutex&, thus you can safely use Mutex::Lock with a * StaticMutex. */ struct StaticMutex { void lock(); bool trylock(); void unlock(); operator Mutex&(); GStaticMutex* gobj() { return &gobject_; } #ifndef DOXYGEN_SHOULD_SKIP_THIS // Must be public to allow initialization at compile time. GStaticMutex gobject_; #endif }; /** Represents a mutex (mutual exclusion). * It can be used to protect data against shared access. Try to use * Mutex::Lock instead of calling lock() and unlock() directly -- * it will make your life much easier. * * @note Before creating a Glib::Mutex, Glib::thread_init() has to be called. * * @note Glib::Mutex is not recursive, i.e. a thread will deadlock, if it * already has locked the mutex while calling lock(). Use Glib::RecMutex * instead, if you need recursive mutexes. */ class Mutex { public: class Lock; Mutex(); ~Mutex(); /** Locks the mutex. * If mutex is already locked by another thread, the current thread will * block until mutex is unlocked by the other thread. * @see Mutex::Lock */ void lock(); /** Tries to lock the mutex. * If the mutex is already locked by another thread, it immediately returns * @c false. Otherwise it locks the mutex and returns @c true. * @return Whether the mutex could be locked. * @see Mutex::Lock */ bool trylock(); /** Unlocks the mutex. * If another thread is blocked in a lock() call for this mutex, it will be * woken and can lock the mutex itself. * @see Mutex::Lock */ void unlock(); GMutex* gobj() { return gobject_; } private: GMutex* gobject_; // noncopyable Mutex(const Mutex&); Mutex& operator=(const Mutex&); }; /** Utility class for exception-safe mutex locking. * @par Usage example: * @code * { * Glib::Mutex::Lock lock (mutex); // calls mutex.lock() * do_something(); * } // the destructor calls mutex.unlock() * @endcode * As you can see, the compiler takes care of the unlocking. This is not * only exception safe but also much less error-prone. You could even * return while still holding the lock and it will be released * properly. */ class Mutex::Lock { public: explicit inline Lock(Mutex& mutex); inline Lock(Mutex& mutex, NotLock); inline Lock(Mutex& mutex, TryLock); inline ~Lock(); inline void acquire(); inline bool try_acquire(); inline void release(); inline bool locked() const; private: Mutex& mutex_; bool locked_; // noncopyable Lock(const Mutex::Lock&); Mutex::Lock& operator=(const Mutex::Lock&); }; /** Like Glib::RecMutex, but can be defined at compile time. * Use @c GLIBMM_STATIC_REC_MUTEX_INIT to initialize a StaticRecMutex: * @code * Glib::StaticRecMutex mutex = GLIBMM_STATIC_REC_MUTEX_INIT; * @endcode * A StaticRecMutex can be used without calling Glib::thread_init(), it will * silently do nothing then. That will also work when using the implicit * conversion to RecMutex&, thus you can safely use RecMutex::Lock with a * StaticRecMutex. */ struct StaticRecMutex { void lock(); bool trylock(); void unlock(); void lock_full(unsigned int depth); unsigned int unlock_full(); operator RecMutex&(); GStaticRecMutex* gobj() { return &gobject_; } #ifndef DOXYGEN_SHOULD_SKIP_THIS // Must be public to allow initialization at compile time. GStaticRecMutex gobject_; #endif }; class RecMutex : public StaticRecMutex { public: class Lock; RecMutex(); ~RecMutex(); private: // noncopyable RecMutex(const RecMutex&); RecMutex& operator=(const RecMutex&); }; /** Utility class for exception-safe locking of recursive mutexes. */ class RecMutex::Lock { public: explicit inline Lock(RecMutex& mutex); inline Lock(RecMutex& mutex, NotLock); inline Lock(RecMutex& mutex, TryLock); inline ~Lock(); inline void acquire(); inline bool try_acquire(); inline void release(); inline bool locked() const; private: RecMutex& mutex_; bool locked_; // noncopyable Lock(const RecMutex::Lock&); RecMutex::Lock& operator=(const RecMutex::Lock&); }; /** Like Glib::RWLock, but can be defined at compile time. * Use @c GLIBMM_STATIC_RW_LOCK_INIT to initialize a StaticRWLock: * @code * Glib::StaticRWLock rw_lock = GLIBMM_STATIC_RW_LOCK_INIT; * @endcode * A StaticRWLock can be used without calling Glib::thread_init(), it will * silently do nothing then. That will also work when using the implicit * conversion to RWLock&, thus you can safely use RWLock::ReaderLock and * RWLock::WriterLock with a StaticRWLock. */ struct StaticRWLock { void reader_lock(); bool reader_trylock(); void reader_unlock(); void writer_lock(); bool writer_trylock(); void writer_unlock(); operator RWLock&(); GStaticRWLock* gobj() { return &gobject_; } #ifndef DOXYGEN_SHOULD_SKIP_THIS // Must be public to allow initialization at compile time. GStaticRWLock gobject_; #endif }; class RWLock : public StaticRWLock { public: class ReaderLock; class WriterLock; RWLock(); ~RWLock(); private: // noncopyable RWLock(const RWLock&); RWLock& operator=(const RWLock&); }; /** Utility class for exception-safe locking of read/write locks. */ class RWLock::ReaderLock { public: explicit inline ReaderLock(RWLock& rwlock); inline ReaderLock(RWLock& rwlock, NotLock); inline ReaderLock(RWLock& rwlock, TryLock); inline ~ReaderLock(); inline void acquire(); inline bool try_acquire(); inline void release(); inline bool locked() const; private: RWLock& rwlock_; bool locked_; // noncopyable ReaderLock(const RWLock::ReaderLock&); RWLock::ReaderLock& operator=(const RWLock::ReaderLock&); }; /** Utility class for exception-safe locking of read/write locks. */ class RWLock::WriterLock { public: explicit inline WriterLock(RWLock& rwlock); inline WriterLock(RWLock& rwlock, NotLock); inline WriterLock(RWLock& rwlock, TryLock); inline ~WriterLock(); inline void acquire(); inline bool try_acquire(); inline void release(); inline bool locked() const; private: RWLock& rwlock_; bool locked_; // noncopyable WriterLock(const RWLock::WriterLock&); RWLock::WriterLock& operator=(const RWLock::WriterLock&); }; /** An opaque data structure to represent a condition. * A @a Cond is an object that threads can block on, if they find a certain * condition to be false. If other threads change the state of this condition * they can signal the @a Cond, such that the waiting thread is woken up. * @par Usage example: * @code * Glib::Cond data_cond; * Glib::Mutex data_mutex; * void* current_data = NULL; * * void push_data (void* data) * { * data_mutex.lock(); * current_data = data; * data_cond.signal(); * data_mutex.unlock(); * } * * void* pop_data () * { * void* data; * * data_mutex.lock(); * while (!current_data) * data_cond.wait(data_mutex); * data = current_data; * current_data = NULL; * data_mutex.unlock(); * return data; * } * @endcode */ class Cond { public: Cond(); ~Cond(); /** If threads are waiting for this @a Cond, exactly one of them is woken up. * It is good practice to hold the same lock as the waiting thread, while calling * this method, though not required. * * @note This method can also be used if @a Glib::thread_init() has not yet been * called and will do nothing then. */ void signal(); /** If threads are waiting for this @a Cond, all of them are woken up. * It is good practice to hold the same lock as the waiting thread, while calling * this method, though not required. * * @note This method can also be used if @a Glib::thread_init() has not yet been * called and will do nothing then. */ void broadcast(); /** Waits until this thread is woken up on this @a Cond. * The mutex is unlocked before falling asleep and locked again before resuming. * * This method can also be used if @a Glib::thread_init() has not yet been * called and will immediately return then. * * @param mutex a @a Mutex that is currently locked. * * @note It is important to use the @a wait() and @a timed_wait() methods * only inside a loop, which checks for the condition to be true as it is not * guaranteed that the waiting thread will find it fulfilled, even if the signaling * thread left the condition in that state. This is because another thread can have * altered the condition, before the waiting thread got the chance to be woken up, * even if the condition itself is protected by a @a Mutex. */ void wait(Mutex& mutex); /** Waits until this thread is woken up on this @a Cond, but not longer than until the time, that is specified by @a abs_time. * The mutex is unlocked before falling asleep and locked again before resuming. * * This function can also be used, if @a Glib::thread_init() has not yet been * called and will immediately return @c true then. * * @param mutex a @a Mutex that is currently locked. * @param abs_time a max time to wait. * * @note It is important to use the @a wait() and @a timed_wait() methods * only inside a loop, which checks for the condition to be true as it is not * guaranteed that the waiting thread will find it fulfilled, even if the signaling * thread left the condition in that state. This is because another thread can have * altered the condition, before the waiting thread got the chance to be woken up, * even if the condition itself is protected by a @a Mutex. */ bool timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time); GCond* gobj() { return gobject_; } private: GCond* gobject_; // noncopyable Cond(const Cond&); Cond& operator=(const Cond&); }; template struct StaticPrivate { typedef void (*DestroyNotifyFunc) (void*); static void delete_ptr(void* data); inline T* get(); inline void set(T* data, DestroyNotifyFunc notify_func = &StaticPrivate::delete_ptr); GStaticPrivate* gobj() { return &gobject_; } #ifndef DOXYGEN_SHOULD_SKIP_THIS // Must be public to allow initialization at compile time. GStaticPrivate gobject_; #endif }; template class Private { public: typedef void (*DestructorFunc) (void*); static void delete_ptr(void* data); explicit inline Private(DestructorFunc destructor_func = &Private::delete_ptr); inline T* get(); inline void set(T* data); GPrivate* gobj() { return gobject_; } private: GPrivate* gobject_; // noncopyable Private(const Private&); Private& operator=(const Private&); }; /** @} group Threads */ /*! A glibmm thread example. * @example thread/thread.cc */ #ifndef DOXYGEN_SHOULD_SKIP_THIS /***************************************************************************/ /* inline implementation */ /***************************************************************************/ // internal void thread_init_impl(); /* This function must be inline, to avoid an unnecessary dependency on * libgthread even if the thread system is not used. libgthread might * not even be available if GLib was compiled without thread support. */ inline void thread_init(GThreadFunctions* vtable) { g_thread_init(vtable); Glib::thread_init_impl(); } inline bool thread_supported() { //MSVC++ needs the != 0 to avoid an int -> bool cast warning. return (g_thread_supported() != 0); } /**** Glib::Mutex::Lock ****************************************************/ inline Mutex::Lock::Lock(Mutex& mutex) : mutex_ (mutex), locked_ (true) { mutex_.lock(); } inline Mutex::Lock::Lock(Mutex& mutex, NotLock) : mutex_ (mutex), locked_ (false) {} inline Mutex::Lock::Lock(Mutex& mutex, TryLock) : mutex_ (mutex), locked_ (mutex.trylock()) {} inline Mutex::Lock::~Lock() { if(locked_) mutex_.unlock(); } inline void Mutex::Lock::acquire() { mutex_.lock(); locked_ = true; } inline bool Mutex::Lock::try_acquire() { locked_ = mutex_.trylock(); return locked_; } inline void Mutex::Lock::release() { mutex_.unlock(); locked_ = false; } inline bool Mutex::Lock::locked() const { return locked_; } /**** Glib::RecMutex::Lock *************************************************/ inline RecMutex::Lock::Lock(RecMutex& mutex) : mutex_ (mutex), locked_ (true) { mutex_.lock(); } inline RecMutex::Lock::Lock(RecMutex& mutex, NotLock) : mutex_ (mutex), locked_ (false) {} inline RecMutex::Lock::Lock(RecMutex& mutex, TryLock) : mutex_ (mutex), locked_ (mutex.trylock()) {} inline RecMutex::Lock::~Lock() { if(locked_) mutex_.unlock(); } inline void RecMutex::Lock::acquire() { mutex_.lock(); locked_ = true; } inline bool RecMutex::Lock::try_acquire() { locked_ = mutex_.trylock(); return locked_; } inline void RecMutex::Lock::release() { mutex_.unlock(); locked_ = false; } inline bool RecMutex::Lock::locked() const { return locked_; } /**** Glib::RWLock::ReaderLock *********************************************/ inline RWLock::ReaderLock::ReaderLock(RWLock& rwlock) : rwlock_ (rwlock), locked_ (true) { rwlock_.reader_lock(); } inline RWLock::ReaderLock::ReaderLock(RWLock& rwlock, NotLock) : rwlock_ (rwlock), locked_ (false) {} inline RWLock::ReaderLock::ReaderLock(RWLock& rwlock, TryLock) : rwlock_ (rwlock), locked_ (rwlock.reader_trylock()) {} inline RWLock::ReaderLock::~ReaderLock() { if(locked_) rwlock_.reader_unlock(); } inline void RWLock::ReaderLock::acquire() { rwlock_.reader_lock(); locked_ = true; } inline bool RWLock::ReaderLock::try_acquire() { locked_ = rwlock_.reader_trylock(); return locked_; } inline void RWLock::ReaderLock::release() { rwlock_.reader_unlock(); locked_ = false; } inline bool RWLock::ReaderLock::locked() const { return locked_; } /**** Glib::RWLock::WriterLock *********************************************/ inline RWLock::WriterLock::WriterLock(RWLock& rwlock) : rwlock_ (rwlock), locked_ (true) { rwlock_.writer_lock(); } inline RWLock::WriterLock::WriterLock(RWLock& rwlock, NotLock) : rwlock_ (rwlock), locked_ (false) {} inline RWLock::WriterLock::WriterLock(RWLock& rwlock, TryLock) : rwlock_ (rwlock), locked_ (rwlock.writer_trylock()) {} inline RWLock::WriterLock::~WriterLock() { if(locked_) rwlock_.writer_unlock(); } inline void RWLock::WriterLock::acquire() { rwlock_.writer_lock(); locked_ = true; } inline bool RWLock::WriterLock::try_acquire() { locked_ = rwlock_.writer_trylock(); return locked_; } inline void RWLock::WriterLock::release() { rwlock_.writer_unlock(); locked_ = false; } inline bool RWLock::WriterLock::locked() const { return locked_; } /**** Glib::StaticPrivate **************************************************/ // static template void StaticPrivate::delete_ptr(void* data) { delete static_cast(data); } template inline T* StaticPrivate::get() { return static_cast(g_static_private_get(&gobject_)); } template inline void StaticPrivate::set(T* data, typename StaticPrivate::DestroyNotifyFunc notify_func) { g_static_private_set(&gobject_, data, notify_func); } /**** Glib::Private ********************************************************/ // static template void Private::delete_ptr(void* data) { delete static_cast(data); } template inline Private::Private(typename Private::DestructorFunc destructor_func) : gobject_ (g_private_new(destructor_func)) {} template inline T* Private::get() { return static_cast(g_private_get(gobject_)); } template inline void Private::set(T* data) { g_private_set(gobject_, data); } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ } // namespace Glib #endif /* _GLIBMM_THREAD_H */