1 /* $Id: thread.hg,v 1.13 2005/01/21 12:48:05 murrayc Exp $ */
3 /* Copyright (C) 2002 The gtkmm Development Team
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <sigc++/sigc++.h>
26 #include <glibmm/error.h>
27 #include <glibmm/timeval.h>
29 /* Shadow THREAD_PRIORITY_NORMAL macro (from winbase.h).
31 #if defined(THREAD_PRIORITY_NORMAL) && !defined(GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL)
32 enum { GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL = THREAD_PRIORITY_NORMAL };
33 #undef THREAD_PRIORITY_NORMAL
34 enum { THREAD_PRIORITY_NORMAL = GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL };
35 #define THREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
36 #define GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL 1
40 /** Initializer macro for Glib::StaticMutex.
41 * @relates Glib::StaticMutex
44 #define GLIBMM_STATIC_MUTEX_INIT { G_STATIC_MUTEX_INIT }
46 /** Initializer macro for Glib::StaticRecMutex.
47 * @relates Glib::StaticRecMutex
50 #define GLIBMM_STATIC_REC_MUTEX_INIT { G_STATIC_REC_MUTEX_INIT }
52 /** Initializer macro for Glib::StaticRWLock.
53 * @relates Glib::StaticRWLock
56 #define GLIBMM_STATIC_RW_LOCK_INIT { G_STATIC_RW_LOCK_INIT }
58 /** Initializer macro for Glib::StaticPrivate.
59 * @relates Glib::StaticPrivate
62 #define GLIBMM_STATIC_PRIVATE_INIT { G_STATIC_PRIVATE_INIT }
68 /** Specifies the priority of a thread.
69 * @note It is not guaranteed, that threads with different priorities really
70 * behave accordingly. On some systems (e.g. Linux) only <tt>root</tt> can
71 * increase priorities. On other systems (e.g. Solaris) there doesn't seem to
72 * be different scheduling for different priorities. All in all try to avoid
73 * being dependent on priorities.
75 _WRAP_ENUM(ThreadPriority, GThreadPriority, NO_GTYPE)
77 /*! @var ThreadPriority THREAD_PRIORITY_LOW
78 * A priority lower than normal.
80 /*! @var ThreadPriority THREAD_PRIORITY_NORMAL
81 * The default priority.
83 /*! @var ThreadPriority THREAD_PRIORITY_HIGH
84 * A priority higher than normal.
86 /*! @var ThreadPriority THREAD_PRIORITY_URGENT
87 * The highest priority.
91 /** @defgroup Threads Threads
92 * Thread abstraction; including threads, different mutexes,
93 * conditions and thread private data.
97 enum NotLock { NOT_LOCK };
98 enum TryLock { TRY_LOCK };
100 /** Initializes the GLib thread system.
101 * Before you use a thread related function in glibmm, you should initialize
102 * the thread system. This is done by calling Glib::thread_init().
104 * @note You should only call thread_init() with a non-<tt>0</tt> parameter
105 * if you really know what you are doing.
107 * @note thread_init() must not be called directly or indirectly as
108 * a callback from glibmm. Also no mutexes may be currently locked while
109 * calling thread_init().
111 * thread_init() might only be called once. On the second call it will
112 * abort with an error. If you want to make sure that the thread system
113 * is initialized, you can do that too:
115 * if(!Glib::thread_supported()) Glib::thread_init();
117 * After that line either the thread system is initialized, or the program
118 * will abort if no thread system is available in GLib, i.e. either
119 * @c G_THREADS_ENABLED is not defined or @c G_THREADS_IMPL_NONE is defined.
121 * If no thread system is available and @a vtable is <tt>0</tt> or if not all
122 * elements of @a vtable are non-<tt>0</tt>, then thread_init() will abort.
124 * @note To use thread_init() in your program, you have to link with the
125 * libraries that the command <tt>pkg-config --libs gthread-2.0</tt>
126 * outputs. This is not the case for all the other thread related functions
127 * of glibmm. Those can be used without having to link with the thread
128 * libraries. (You @em have to link with <tt>gthread-2.0</tt> if you actually
129 * want to use threads in your application, though.)
131 * @param vtable A function table of type @c GThreadFunctions, that provides
132 * the entry points to the thread system to be used.
134 inline void thread_init(GThreadFunctions* vtable = 0);
136 /** Returns whether the thread system is initialized.
137 * @return @c true, if the thread system is initialized.
139 inline bool thread_supported();
146 struct StaticRecMutex;
150 /** Exception class for thread-related errors.
152 _WRAP_GERROR(ThreadError, GThreadError, G_THREAD_ERROR, NO_GTYPE)
155 /** Represents a running thread.
156 * An instance of this class can only be obtained with create(), self(),
157 * or wrap(GThread*). It's not possible to delete a Thread object. If the
158 * thread is @em not joinable, its resources will be freed automatically
159 * when it exits. Otherwise, if the thread @em is joinable, you must call
160 * join() to avoid a memory leak.
162 * @note g_thread_exit() is not wrapped, because that function exits a thread
163 * without any cleanup. That's especially dangerous in C++ code, since the
164 * destructors of automatic objects won't be invoked. Instead, you can throw
165 * a Thread::Exit exception, which will be caught by the internal thread
168 * @note You might have noticed that the thread entry slot doesn't have the
169 * usual void* return value. If you want to return any data from your thread
170 * you can pass an additional output argument to the thread's entry slot.
177 //See http://bugzilla.gnome.org/show_bug.cgi?id=512348 about the sigc::trackable issue.
178 /** Creates a new thread with the priority <tt>THREAD_PRIORITY_NORMAL</tt>.
179 * If @a joinable is @c true, you can wait for this thread's termination by
180 * calling join(). Otherwise the thread will just disappear, when ready.
182 * The new thread executes the function or method @a slot points to. You can
183 * pass additional arguments using sigc::bind(). If the thread was created
184 * successfully, it is returned, otherwise a ThreadError exception is thrown.
186 * Because sigc::trackable is not thread safe, if the slot represents a
187 * non-static class method (that is, it is created by sigc::mem_fun()), the
188 * class concerned should not derive from sigc::trackable.
190 * @param slot A slot to execute in the new thread.
191 * @param joinable Should this thread be joinable?
192 * @return The new Thread* on success.
193 * @throw Glib::ThreadError
195 static Thread* create(const sigc::slot<void>& slot, bool joinable);
197 //See http://bugzilla.gnome.org/show_bug.cgi?id=512348 about the sigc::trackable issue.
198 /** Creates a new thread with the priority @a priority. The stack gets the
199 * size @a stack_size or the default value for the current platform, if
200 * @a stack_size is <tt>0</tt>.
202 * If @a joinable is @c true, you can wait for this thread's termination by
203 * calling join(). Otherwise the thread will just disappear, when ready.
204 * If @a bound is @c true, this thread will be scheduled in the system scope,
205 * otherwise the implementation is free to do scheduling in the process
206 * scope. The first variant is more expensive resource-wise, but generally
207 * faster. On some systems (e.g. Linux) all threads are bound.
209 * The new thread executes the function or method @a slot points to. You can
210 * pass additional arguments using sigc::bind(). If the thread was created
211 * successfully, it is returned.
213 * Because sigc::trackable is not thread safe, if the slot represents a
214 * non-static class method (that is, it is created by sigc::mem_fun()), the
215 * class concerned should not derive from sigc::trackable.
217 * @note It is not guaranteed, that threads with different priorities really
218 * behave accordingly. On some systems (e.g. Linux) only root can increase
219 * priorities. On other systems (e.g. Solaris) there doesn't seem to be
220 * different scheduling for different priorities. All in all try to avoid
221 * being dependent on priorities. Use <tt>Glib::THREAD_PRIORITY_NORMAL</tt>
224 * @note Only use the extended
225 * create(const sigc::slot<void>&, unsigned long, bool, bool, ThreadPriority)
226 * function, when you really can't use the simple
227 * create(const sigc::slot<void>&, bool)
228 * instead. The latter overload does not take @a stack_size, @a bound and
229 * @a priority as arguments, as they should only be used for cases, where
232 * @param slot A slot to execute in the new thread.
233 * @param stack_size A stack size for the new thread, or <tt>0</tt>.
234 * @param joinable Should this thread be joinable?
235 * @param bound Should this thread be bound to a system thread?
236 * @param priority A priority for the thread.
237 * @return The new Thread* on success.
238 * @throw Glib::ThreadError
240 static Thread* create(const sigc::slot<void>& slot, unsigned long stack_size,
241 bool joinable, bool bound, ThreadPriority priority);
243 /** Returns the Thread* corresponding to the calling thread.
244 * @return The current thread.
246 static Thread* self();
248 /** Returns whether the thread is joinable.
249 * @return Whether the thread is joinable.
251 bool joinable() const;
253 /** Waits until the thread finishes.
254 * Waits until the thread finishes, i.e. the slot, as given to create(),
255 * returns or g_thread_exit() is called by the thread. (Calling
256 * g_thread_exit() in a C++ program should be avoided.) All resources of
257 * the thread including the Glib::Thread object are released. The thread
258 * must have been created with <tt>joinable = true</tt>.
262 /** Changes the priority of the thread to @a priority.
263 * @note It is not guaranteed, that threads with different priorities really
264 * behave accordingly. On some systems (e.g. Linux) only @c root can
265 * increase priorities. On other systems (e.g. Solaris) there doesn't seem
266 * to be different scheduling for different priorities. All in all try to
267 * avoid being dependent on priorities.
268 * @param priority A new priority for the thread.
270 void set_priority(ThreadPriority priority);
272 /** Returns the priority of the thread.
273 * @return The thread's priority.
275 ThreadPriority get_priority() const;
277 /** Gives way to other threads waiting to be scheduled.
278 * This function is often used as a method to make busy wait less evil. But
279 * in most cases, you will encounter, there are better methods to do that.
280 * So in general you shouldn't use this function.
284 GThread* gobj() { return &gobject_; }
285 const GThread* gobj() const { return &gobject_; }
290 // Glib::Thread can neither be constructed nor deleted.
292 void operator delete(void*, size_t);
295 Thread(const Thread&);
296 Thread& operator=(const Thread&);
299 /** %Exception class used to exit from a thread.
301 * throw Glib::Thread::Exit();
303 * Write this if you want to exit from a thread created by Thread::create().
304 * Of course you must make sure not to catch Thread::Exit by accident, i.e.
305 * when using <tt>catch(...)</tt> somewhere in your code.
310 /** @relates Glib::Thread */
311 Thread* wrap(GThread* gobject);
314 /** Like Glib::Mutex, but can be defined at compile time.
315 * Use @c GLIBMM_STATIC_MUTEX_INIT to initialize a StaticMutex:
317 * Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
319 * A StaticMutex can be used without calling Glib::thread_init(), it will
320 * silently do nothing then. That will also work when using the implicit
321 * conversion to Mutex&, thus you can safely use Mutex::Lock with a
332 GStaticMutex* gobj() { return &gobject_; }
334 #ifndef DOXYGEN_SHOULD_SKIP_THIS
335 // Must be public to allow initialization at compile time.
336 GStaticMutex gobject_;
340 /** Represents a mutex (mutual exclusion).
341 * It can be used to protect data against shared access. Try to use
342 * Mutex::Lock instead of calling lock() and unlock() directly --
343 * it will make your life much easier.
345 * @note Before creating a Glib::Mutex, Glib::thread_init() has to be called.
347 * @note Glib::Mutex is not recursive, i.e. a thread will deadlock, if it
348 * already has locked the mutex while calling lock(). Use Glib::RecMutex
349 * instead, if you need recursive mutexes.
360 * If mutex is already locked by another thread, the current thread will
361 * block until mutex is unlocked by the other thread.
366 /** Tries to lock the mutex.
367 * If the mutex is already locked by another thread, it immediately returns
368 * @c false. Otherwise it locks the mutex and returns @c true.
369 * @return Whether the mutex could be locked.
374 /** Unlocks the mutex.
375 * If another thread is blocked in a lock() call for this mutex, it will be
376 * woken and can lock the mutex itself.
381 GMutex* gobj() { return gobject_; }
388 Mutex& operator=(const Mutex&);
391 /** Utility class for exception-safe mutex locking.
392 * @par Usage example:
395 * Glib::Mutex::Lock lock (mutex); // calls mutex.lock()
397 * } // the destructor calls mutex.unlock()
399 * As you can see, the compiler takes care of the unlocking. This is not
400 * only exception safe but also much less error-prone. You could even
401 * <tt>return</tt> while still holding the lock and it will be released
407 explicit inline Lock(Mutex& mutex);
408 inline Lock(Mutex& mutex, NotLock);
409 inline Lock(Mutex& mutex, TryLock);
412 inline void acquire();
413 inline bool try_acquire();
414 inline void release();
415 inline bool locked() const;
422 Lock(const Mutex::Lock&);
423 Mutex::Lock& operator=(const Mutex::Lock&);
427 /** Like Glib::RecMutex, but can be defined at compile time.
428 * Use @c GLIBMM_STATIC_REC_MUTEX_INIT to initialize a StaticRecMutex:
430 * Glib::StaticRecMutex mutex = GLIBMM_STATIC_REC_MUTEX_INIT;
432 * A StaticRecMutex can be used without calling Glib::thread_init(), it will
433 * silently do nothing then. That will also work when using the implicit
434 * conversion to RecMutex&, thus you can safely use RecMutex::Lock with a
437 struct StaticRecMutex
443 void lock_full(unsigned int depth);
444 unsigned int unlock_full();
446 operator RecMutex&();
448 GStaticRecMutex* gobj() { return &gobject_; }
450 #ifndef DOXYGEN_SHOULD_SKIP_THIS
451 // Must be public to allow initialization at compile time.
452 GStaticRecMutex gobject_;
456 class RecMutex : public StaticRecMutex
466 RecMutex(const RecMutex&);
467 RecMutex& operator=(const RecMutex&);
470 /** Utility class for exception-safe locking of recursive mutexes.
475 explicit inline Lock(RecMutex& mutex);
476 inline Lock(RecMutex& mutex, NotLock);
477 inline Lock(RecMutex& mutex, TryLock);
480 inline void acquire();
481 inline bool try_acquire();
482 inline void release();
483 inline bool locked() const;
490 Lock(const RecMutex::Lock&);
491 RecMutex::Lock& operator=(const RecMutex::Lock&);
495 /** Like Glib::RWLock, but can be defined at compile time.
496 * Use @c GLIBMM_STATIC_RW_LOCK_INIT to initialize a StaticRWLock:
498 * Glib::StaticRWLock rw_lock = GLIBMM_STATIC_RW_LOCK_INIT;
500 * A StaticRWLock can be used without calling Glib::thread_init(), it will
501 * silently do nothing then. That will also work when using the implicit
502 * conversion to RWLock&, thus you can safely use RWLock::ReaderLock and
503 * RWLock::WriterLock with a StaticRWLock.
508 bool reader_trylock();
509 void reader_unlock();
512 bool writer_trylock();
513 void writer_unlock();
517 GStaticRWLock* gobj() { return &gobject_; }
519 #ifndef DOXYGEN_SHOULD_SKIP_THIS
520 // Must be public to allow initialization at compile time.
521 GStaticRWLock gobject_;
525 class RWLock : public StaticRWLock
536 RWLock(const RWLock&);
537 RWLock& operator=(const RWLock&);
540 /** Utility class for exception-safe locking of read/write locks.
542 class RWLock::ReaderLock
545 explicit inline ReaderLock(RWLock& rwlock);
546 inline ReaderLock(RWLock& rwlock, NotLock);
547 inline ReaderLock(RWLock& rwlock, TryLock);
548 inline ~ReaderLock();
550 inline void acquire();
551 inline bool try_acquire();
552 inline void release();
553 inline bool locked() const;
560 ReaderLock(const RWLock::ReaderLock&);
561 RWLock::ReaderLock& operator=(const RWLock::ReaderLock&);
564 /** Utility class for exception-safe locking of read/write locks.
566 class RWLock::WriterLock
569 explicit inline WriterLock(RWLock& rwlock);
570 inline WriterLock(RWLock& rwlock, NotLock);
571 inline WriterLock(RWLock& rwlock, TryLock);
572 inline ~WriterLock();
574 inline void acquire();
575 inline bool try_acquire();
576 inline void release();
577 inline bool locked() const;
584 WriterLock(const RWLock::WriterLock&);
585 RWLock::WriterLock& operator=(const RWLock::WriterLock&);
588 /** An opaque data structure to represent a condition.
589 * A @a Cond is an object that threads can block on, if they find a certain
590 * condition to be false. If other threads change the state of this condition
591 * they can signal the @a Cond, such that the waiting thread is woken up.
592 * @par Usage example:
594 * Glib::Cond data_cond;
595 * Glib::Mutex data_mutex;
596 * void* current_data = NULL;
598 * void push_data (void* data)
601 * current_data = data;
602 * data_cond.signal();
603 * data_mutex.unlock();
611 * while (!current_data)
612 * data_cond.wait(data_mutex);
613 * data = current_data;
614 * current_data = NULL;
615 * data_mutex.unlock();
626 /** If threads are waiting for this @a Cond, exactly one of them is woken up.
627 * It is good practice to hold the same lock as the waiting thread, while calling
628 * this method, though not required.
630 * @note This method can also be used if @a Glib::thread_init() has not yet been
631 * called and will do nothing then.
635 /** If threads are waiting for this @a Cond, all of them are woken up.
636 * It is good practice to hold the same lock as the waiting thread, while calling
637 * this method, though not required.
639 * @note This method can also be used if @a Glib::thread_init() has not yet been
640 * called and will do nothing then.
644 /** Waits until this thread is woken up on this @a Cond.
645 * The mutex is unlocked before falling asleep and locked again before resuming.
647 * This method can also be used if @a Glib::thread_init() has not yet been
648 * called and will immediately return then.
650 * @param mutex a @a Mutex that is currently locked.
652 * @note It is important to use the @a wait() and @a timed_wait() methods
653 * only inside a loop, which checks for the condition to be true as it is not
654 * guaranteed that the waiting thread will find it fulfilled, even if the signaling
655 * thread left the condition in that state. This is because another thread can have
656 * altered the condition, before the waiting thread got the chance to be woken up,
657 * even if the condition itself is protected by a @a Mutex.
659 void wait(Mutex& mutex);
661 /** 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.
662 * The mutex is unlocked before falling asleep and locked again before resuming.
664 * This function can also be used, if @a Glib::thread_init() has not yet been
665 * called and will immediately return @c true then.
667 * @param mutex a @a Mutex that is currently locked.
668 * @param abs_time a max time to wait.
670 * @note It is important to use the @a wait() and @a timed_wait() methods
671 * only inside a loop, which checks for the condition to be true as it is not
672 * guaranteed that the waiting thread will find it fulfilled, even if the signaling
673 * thread left the condition in that state. This is because another thread can have
674 * altered the condition, before the waiting thread got the chance to be woken up,
675 * even if the condition itself is protected by a @a Mutex.
677 bool timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time);
679 GCond* gobj() { return gobject_; }
686 Cond& operator=(const Cond&);
693 typedef void (*DestroyNotifyFunc) (void*);
695 static void delete_ptr(void* data);
698 inline void set(T* data, DestroyNotifyFunc notify_func = &StaticPrivate<T>::delete_ptr);
700 GStaticPrivate* gobj() { return &gobject_; }
702 #ifndef DOXYGEN_SHOULD_SKIP_THIS
703 // Must be public to allow initialization at compile time.
704 GStaticPrivate gobject_;
712 typedef void (*DestructorFunc) (void*);
714 static void delete_ptr(void* data);
716 explicit inline Private(DestructorFunc destructor_func = &Private<T>::delete_ptr);
718 inline void set(T* data);
720 GPrivate* gobj() { return gobject_; }
726 Private(const Private<T>&);
727 Private<T>& operator=(const Private<T>&);
730 /** @} group Threads */
732 /*! A glibmm thread example.
733 * @example thread/thread.cc
737 #ifndef DOXYGEN_SHOULD_SKIP_THIS
739 /***************************************************************************/
740 /* inline implementation */
741 /***************************************************************************/
744 void thread_init_impl();
746 /* This function must be inline, to avoid an unnecessary dependency on
747 * libgthread even if the thread system is not used. libgthread might
748 * not even be available if GLib was compiled without thread support.
751 void thread_init(GThreadFunctions* vtable)
753 g_thread_init(vtable);
754 Glib::thread_init_impl();
758 bool thread_supported()
760 //MSVC++ needs the != 0 to avoid an int -> bool cast warning.
761 return (g_thread_supported() != 0);
765 /**** Glib::Mutex::Lock ****************************************************/
768 Mutex::Lock::Lock(Mutex& mutex)
777 Mutex::Lock::Lock(Mutex& mutex, NotLock)
784 Mutex::Lock::Lock(Mutex& mutex, TryLock)
787 locked_ (mutex.trylock())
798 void Mutex::Lock::acquire()
805 bool Mutex::Lock::try_acquire()
807 locked_ = mutex_.trylock();
812 void Mutex::Lock::release()
819 bool Mutex::Lock::locked() const
825 /**** Glib::RecMutex::Lock *************************************************/
828 RecMutex::Lock::Lock(RecMutex& mutex)
837 RecMutex::Lock::Lock(RecMutex& mutex, NotLock)
844 RecMutex::Lock::Lock(RecMutex& mutex, TryLock)
847 locked_ (mutex.trylock())
851 RecMutex::Lock::~Lock()
858 void RecMutex::Lock::acquire()
865 bool RecMutex::Lock::try_acquire()
867 locked_ = mutex_.trylock();
872 void RecMutex::Lock::release()
879 bool RecMutex::Lock::locked() const
885 /**** Glib::RWLock::ReaderLock *********************************************/
888 RWLock::ReaderLock::ReaderLock(RWLock& rwlock)
893 rwlock_.reader_lock();
897 RWLock::ReaderLock::ReaderLock(RWLock& rwlock, NotLock)
904 RWLock::ReaderLock::ReaderLock(RWLock& rwlock, TryLock)
907 locked_ (rwlock.reader_trylock())
911 RWLock::ReaderLock::~ReaderLock()
914 rwlock_.reader_unlock();
918 void RWLock::ReaderLock::acquire()
920 rwlock_.reader_lock();
925 bool RWLock::ReaderLock::try_acquire()
927 locked_ = rwlock_.reader_trylock();
932 void RWLock::ReaderLock::release()
934 rwlock_.reader_unlock();
939 bool RWLock::ReaderLock::locked() const
945 /**** Glib::RWLock::WriterLock *********************************************/
948 RWLock::WriterLock::WriterLock(RWLock& rwlock)
953 rwlock_.writer_lock();
957 RWLock::WriterLock::WriterLock(RWLock& rwlock, NotLock)
964 RWLock::WriterLock::WriterLock(RWLock& rwlock, TryLock)
967 locked_ (rwlock.writer_trylock())
971 RWLock::WriterLock::~WriterLock()
974 rwlock_.writer_unlock();
978 void RWLock::WriterLock::acquire()
980 rwlock_.writer_lock();
985 bool RWLock::WriterLock::try_acquire()
987 locked_ = rwlock_.writer_trylock();
992 void RWLock::WriterLock::release()
994 rwlock_.writer_unlock();
999 bool RWLock::WriterLock::locked() const
1005 /**** Glib::StaticPrivate **************************************************/
1009 void StaticPrivate<T>::delete_ptr(void* data)
1011 delete static_cast<T*>(data);
1014 template <class T> inline
1015 T* StaticPrivate<T>::get()
1017 return static_cast<T*>(g_static_private_get(&gobject_));
1020 template <class T> inline
1021 void StaticPrivate<T>::set(T* data, typename StaticPrivate<T>::DestroyNotifyFunc notify_func)
1023 g_static_private_set(&gobject_, data, notify_func);
1027 /**** Glib::Private ********************************************************/
1031 void Private<T>::delete_ptr(void* data)
1033 delete static_cast<T*>(data);
1036 template <class T> inline
1037 Private<T>::Private(typename Private<T>::DestructorFunc destructor_func)
1039 gobject_ (g_private_new(destructor_func))
1042 template <class T> inline
1043 T* Private<T>::get()
1045 return static_cast<T*>(g_private_get(gobject_));
1048 template <class T> inline
1049 void Private<T>::set(T* data)
1051 g_private_set(gobject_, data);
1054 #endif /* DOXYGEN_SHOULD_SKIP_THIS */