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.
22 #include <glib/gthread.h>
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 /** Creates a new thread with the priority <tt>THREAD_PRIORITY_NORMAL</tt>.
178 * If @a joinable is @c true, you can wait for this thread's termination by
179 * calling join(). Otherwise the thread will just disappear, when ready.
181 * The new thread executes the function or method @a slot points to. You can
182 * pass additional arguments using sigc::bind(). If the thread was created
183 * successfully, it is returned, otherwise a ThreadError exception is thrown.
185 * @param slot A slot to execute in the new thread.
186 * @param joinable Should this thread be joinable?
187 * @return The new Thread* on success.
188 * @throw Glib::ThreadError
190 static Thread* create(const sigc::slot<void>& slot, bool joinable);
192 /** Creates a new thread with the priority @a priority. The stack gets the
193 * size @a stack_size or the default value for the current platform, if
194 * @a stack_size is <tt>0</tt>.
196 * If @a joinable is @c true, you can wait for this thread's termination by
197 * calling join(). Otherwise the thread will just disappear, when ready.
198 * If @a bound is @c true, this thread will be scheduled in the system scope,
199 * otherwise the implementation is free to do scheduling in the process
200 * scope. The first variant is more expensive resource-wise, but generally
201 * faster. On some systems (e.g. Linux) all threads are bound.
203 * The new thread executes the function or method @a slot points to. You can
204 * pass additional arguments using sigc::bind(). If the thread was created
205 * successfully, it is returned.
207 * @note It is not guaranteed, that threads with different priorities really
208 * behave accordingly. On some systems (e.g. Linux) only root can increase
209 * priorities. On other systems (e.g. Solaris) there doesn't seem to be
210 * different scheduling for different priorities. All in all try to avoid
211 * being dependent on priorities. Use <tt>Glib::THREAD_PRIORITY_NORMAL</tt>
214 * @note Only use the extended
215 * create(const sigc::slot<void>&, unsigned long, bool, bool, ThreadPriority)
216 * function, when you really can't use the simple
217 * create(const sigc::slot<void>&, bool)
218 * instead. The latter overload does not take @a stack_size, @a bound and
219 * @a priority as arguments, as they should only be used for cases, where
222 * @param slot A slot to execute in the new thread.
223 * @param stack_size A stack size for the new thread, or <tt>0</tt>.
224 * @param joinable Should this thread be joinable?
225 * @param bound Should this thread be bound to a system thread?
226 * @param priority A priority for the thread.
227 * @return The new Thread* on success.
228 * @throw Glib::ThreadError
230 static Thread* create(const sigc::slot<void>& slot, unsigned long stack_size,
231 bool joinable, bool bound, ThreadPriority priority);
233 /** Returns the Thread* corresponding to the calling thread.
234 * @return The current thread.
236 static Thread* self();
238 /** Returns whether the thread is joinable.
239 * @return Whether the thread is joinable.
241 bool joinable() const;
243 /** Waits until the thread finishes.
244 * Waits until the thread finishes, i.e. the slot, as given to create(),
245 * returns or g_thread_exit() is called by the thread. (Calling
246 * g_thread_exit() in a C++ program should be avoided.) All resources of
247 * the thread including the Glib::Thread object are released. The thread
248 * must have been created with <tt>joinable = true</tt>.
252 /** Changes the priority of the thread to @a priority.
253 * @note It is not guaranteed, that threads with different priorities really
254 * behave accordingly. On some systems (e.g. Linux) only @c root can
255 * increase priorities. On other systems (e.g. Solaris) there doesn't seem
256 * to be different scheduling for different priorities. All in all try to
257 * avoid being dependent on priorities.
258 * @param priority A new priority for the thread.
260 void set_priority(ThreadPriority priority);
262 /** Returns the priority of the thread.
263 * @return The thread's priority.
265 ThreadPriority get_priority() const;
267 /** Gives way to other threads waiting to be scheduled.
268 * This function is often used as a method to make busy wait less evil. But
269 * in most cases, you will encounter, there are better methods to do that.
270 * So in general you shouldn't use this function.
274 GThread* gobj() { return &gobject_; }
275 const GThread* gobj() const { return &gobject_; }
280 // Glib::Thread can neither be constructed nor deleted.
282 void operator delete(void*, size_t);
285 Thread(const Thread&);
286 Thread& operator=(const Thread&);
289 /** %Exception class used to exit from a thread.
291 * throw Glib::Thread::Exit();
293 * Write this if you want to exit from a thread created by Thread::create().
294 * Of course you must make sure not to catch Thread::Exit by accident, i.e.
295 * when using <tt>catch(...)</tt> somewhere in your code.
300 /** @relates Glib::Thread */
301 Thread* wrap(GThread* gobject);
304 /** Like Glib::Mutex, but can be defined at compile time.
305 * Use @c GLIBMM_STATIC_MUTEX_INIT to initialize a StaticMutex:
307 * Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
309 * A StaticMutex can be used without calling Glib::thread_init(), it will
310 * silently do nothing then. That will also work when using the implicit
311 * conversion to Mutex&, thus you can safely use Mutex::Lock with a
322 GStaticMutex* gobj() { return &gobject_; }
324 #ifndef DOXYGEN_SHOULD_SKIP_THIS
325 // Must be public to allow initialization at compile time.
326 GStaticMutex gobject_;
330 /** Represents a mutex (mutual exclusion).
331 * It can be used to protect data against shared access. Try to use
332 * Mutex::Lock instead of calling lock() and unlock() directly --
333 * it will make your life much easier.
335 * @note Before creating a Glib::Mutex, Glib::thread_init() has to be called.
337 * @note Glib::Mutex is not recursive, i.e. a thread will deadlock, if it
338 * already has locked the mutex while calling lock(). Use Glib::RecMutex
339 * instead, if you need recursive mutexes.
350 * If mutex is already locked by another thread, the current thread will
351 * block until mutex is unlocked by the other thread.
356 /** Tries to lock the mutex.
357 * If the mutex is already locked by another thread, it immediately returns
358 * @c false. Otherwise it locks the mutex and returns @c true.
359 * @return Whether the mutex could be locked.
364 /** Unlocks the mutex.
365 * If another thread is blocked in a lock() call for this mutex, it will be
366 * woken and can lock the mutex itself.
371 GMutex* gobj() { return gobject_; }
378 Mutex& operator=(const Mutex&);
381 /** Utility class for exception-safe mutex locking.
382 * @par Usage example:
385 * Glib::Mutex::Lock lock (mutex); // calls mutex.lock()
387 * } // the destructor calls mutex.unlock()
389 * As you can see, the compiler takes care of the unlocking. This is not
390 * only exception safe but also much less error-prone. You could even
391 * <tt>return</tt> while still holding the lock and it will be released
397 explicit inline Lock(Mutex& mutex);
398 inline Lock(Mutex& mutex, NotLock);
399 inline Lock(Mutex& mutex, TryLock);
402 inline void acquire();
403 inline bool try_acquire();
404 inline void release();
405 inline bool locked() const;
412 Lock(const Mutex::Lock&);
413 Mutex::Lock& operator=(const Mutex::Lock&);
417 /** Like Glib::RecMutex, but can be defined at compile time.
418 * Use @c GLIBMM_STATIC_REC_MUTEX_INIT to initialize a StaticRecMutex:
420 * Glib::StaticRecMutex mutex = GLIBMM_STATIC_REC_MUTEX_INIT;
422 * A StaticRecMutex can be used without calling Glib::thread_init(), it will
423 * silently do nothing then. That will also work when using the implicit
424 * conversion to RecMutex&, thus you can safely use RecMutex::Lock with a
427 struct StaticRecMutex
433 void lock_full(unsigned int depth);
434 unsigned int unlock_full();
436 operator RecMutex&();
438 GStaticRecMutex* gobj() { return &gobject_; }
440 #ifndef DOXYGEN_SHOULD_SKIP_THIS
441 // Must be public to allow initialization at compile time.
442 GStaticRecMutex gobject_;
446 class RecMutex : public StaticRecMutex
456 RecMutex(const RecMutex&);
457 RecMutex& operator=(const RecMutex&);
460 /** Utility class for exception-safe locking of recursive mutexes.
465 explicit inline Lock(RecMutex& mutex);
466 inline Lock(RecMutex& mutex, NotLock);
467 inline Lock(RecMutex& mutex, TryLock);
470 inline void acquire();
471 inline bool try_acquire();
472 inline void release();
473 inline bool locked() const;
480 Lock(const RecMutex::Lock&);
481 RecMutex::Lock& operator=(const RecMutex::Lock&);
485 /** Like Glib::RWLock, but can be defined at compile time.
486 * Use @c GLIBMM_STATIC_RW_LOCK_INIT to initialize a StaticRWLock:
488 * Glib::StaticRWLock rw_lock = GLIBMM_STATIC_RW_LOCK_INIT;
490 * A StaticRWLock can be used without calling Glib::thread_init(), it will
491 * silently do nothing then. That will also work when using the implicit
492 * conversion to RWLock&, thus you can safely use RWLock::ReaderLock and
493 * RWLock::WriterLock with a StaticRWLock.
498 bool reader_trylock();
499 void reader_unlock();
502 bool writer_trylock();
503 void writer_unlock();
507 GStaticRWLock* gobj() { return &gobject_; }
509 #ifndef DOXYGEN_SHOULD_SKIP_THIS
510 // Must be public to allow initialization at compile time.
511 GStaticRWLock gobject_;
515 class RWLock : public StaticRWLock
526 RWLock(const RWLock&);
527 RWLock& operator=(const RWLock&);
530 /** Utility class for exception-safe locking of read/write locks.
532 class RWLock::ReaderLock
535 explicit inline ReaderLock(RWLock& rwlock);
536 inline ReaderLock(RWLock& rwlock, NotLock);
537 inline ReaderLock(RWLock& rwlock, TryLock);
538 inline ~ReaderLock();
540 inline void acquire();
541 inline bool try_acquire();
542 inline void release();
543 inline bool locked() const;
550 ReaderLock(const RWLock::ReaderLock&);
551 RWLock::ReaderLock& operator=(const RWLock::ReaderLock&);
554 /** Utility class for exception-safe locking of read/write locks.
556 class RWLock::WriterLock
559 explicit inline WriterLock(RWLock& rwlock);
560 inline WriterLock(RWLock& rwlock, NotLock);
561 inline WriterLock(RWLock& rwlock, TryLock);
562 inline ~WriterLock();
564 inline void acquire();
565 inline bool try_acquire();
566 inline void release();
567 inline bool locked() const;
574 WriterLock(const RWLock::WriterLock&);
575 RWLock::WriterLock& operator=(const RWLock::WriterLock&);
578 /** An opaque data structure to represent a condition.
579 * A @a Cond is an object that threads can block on, if they find a certain
580 * condition to be false. If other threads change the state of this condition
581 * they can signal the @a Cond, such that the waiting thread is woken up.
582 * @par Usage example:
584 * Glib::Cond data_cond;
585 * Glib::Mutex data_mutex;
586 * void* current_data = NULL;
588 * void push_data (void* data)
591 * current_data = data;
592 * data_cond.signal();
593 * data_mutex.unlock();
601 * while (!current_data)
602 * data_cond.wait(data_mutex);
603 * data = current_data;
604 * current_data = NULL;
605 * data_mutex.unlock();
616 /** If threads are waiting for this @a Cond, exactly one of them is woken up.
617 * It is good practice to hold the same lock as the waiting thread, while calling
618 * this method, though not required.
620 * @note This method can also be used if @a Glib::thread_init() has not yet been
621 * called and will do nothing then.
625 /** If threads are waiting for this @a Cond, all of them are woken up.
626 * It is good practice to hold the same lock as the waiting thread, while calling
627 * this method, though not required.
629 * @note This method can also be used if @a Glib::thread_init() has not yet been
630 * called and will do nothing then.
634 /** Waits until this thread is woken up on this @a Cond.
635 * The mutex is unlocked before falling asleep and locked again before resuming.
637 * This method can also be used if @a Glib::thread_init() has not yet been
638 * called and will immediately return then.
640 * @param mutex a @a Mutex that is currently locked.
642 * @note It is important to use the @a wait() and @a timed_wait() methods
643 * only inside a loop, which checks for the condition to be true as it is not
644 * guaranteed that the waiting thread will find it fulfilled, even if the signaling
645 * thread left the condition in that state. This is because another thread can have
646 * altered the condition, before the waiting thread got the chance to be woken up,
647 * even if the condition itself is protected by a @a Mutex.
649 void wait(Mutex& mutex);
651 /** 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.
652 * The mutex is unlocked before falling asleep and locked again before resuming.
654 * This function can also be used, if @a Glib::thread_init() has not yet been
655 * called and will immediately return @c true then.
657 * @param mutex a @a Mutex that is currently locked.
658 * @param abs_time a max time to wait.
660 * @note It is important to use the @a wait() and @a timed_wait() methods
661 * only inside a loop, which checks for the condition to be true as it is not
662 * guaranteed that the waiting thread will find it fulfilled, even if the signaling
663 * thread left the condition in that state. This is because another thread can have
664 * altered the condition, before the waiting thread got the chance to be woken up,
665 * even if the condition itself is protected by a @a Mutex.
667 bool timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time);
669 GCond* gobj() { return gobject_; }
676 Cond& operator=(const Cond&);
683 typedef void (*DestroyNotifyFunc) (void*);
685 static void delete_ptr(void* data);
688 inline void set(T* data, DestroyNotifyFunc notify_func = &StaticPrivate<T>::delete_ptr);
690 GStaticPrivate* gobj() { return &gobject_; }
692 #ifndef DOXYGEN_SHOULD_SKIP_THIS
693 // Must be public to allow initialization at compile time.
694 GStaticPrivate gobject_;
702 typedef void (*DestructorFunc) (void*);
704 static void delete_ptr(void* data);
706 explicit inline Private(DestructorFunc destructor_func = &Private<T>::delete_ptr);
708 inline void set(T* data);
710 GPrivate* gobj() { return gobject_; }
716 Private(const Private<T>&);
717 Private<T>& operator=(const Private<T>&);
720 /** @} group Threads */
722 /*! A glibmm thread example.
723 * @example thread/thread.cc
727 #ifndef DOXYGEN_SHOULD_SKIP_THIS
729 /***************************************************************************/
730 /* inline implementation */
731 /***************************************************************************/
734 void thread_init_impl();
736 /* This function must be inline, to avoid an unnecessary dependency on
737 * libgthread even if the thread system is not used. libgthread might
738 * not even be available if GLib was compiled without thread support.
741 void thread_init(GThreadFunctions* vtable)
743 g_thread_init(vtable);
744 Glib::thread_init_impl();
748 bool thread_supported()
750 //MSVC++ needs the != 0 to avoid an int -> bool cast warning.
751 return (g_thread_supported() != 0);
755 /**** Glib::Mutex::Lock ****************************************************/
758 Mutex::Lock::Lock(Mutex& mutex)
767 Mutex::Lock::Lock(Mutex& mutex, NotLock)
774 Mutex::Lock::Lock(Mutex& mutex, TryLock)
777 locked_ (mutex.trylock())
788 void Mutex::Lock::acquire()
795 bool Mutex::Lock::try_acquire()
797 locked_ = mutex_.trylock();
802 void Mutex::Lock::release()
809 bool Mutex::Lock::locked() const
815 /**** Glib::RecMutex::Lock *************************************************/
818 RecMutex::Lock::Lock(RecMutex& mutex)
827 RecMutex::Lock::Lock(RecMutex& mutex, NotLock)
834 RecMutex::Lock::Lock(RecMutex& mutex, TryLock)
837 locked_ (mutex.trylock())
841 RecMutex::Lock::~Lock()
848 void RecMutex::Lock::acquire()
855 bool RecMutex::Lock::try_acquire()
857 locked_ = mutex_.trylock();
862 void RecMutex::Lock::release()
869 bool RecMutex::Lock::locked() const
875 /**** Glib::RWLock::ReaderLock *********************************************/
878 RWLock::ReaderLock::ReaderLock(RWLock& rwlock)
883 rwlock_.reader_lock();
887 RWLock::ReaderLock::ReaderLock(RWLock& rwlock, NotLock)
894 RWLock::ReaderLock::ReaderLock(RWLock& rwlock, TryLock)
897 locked_ (rwlock.reader_trylock())
901 RWLock::ReaderLock::~ReaderLock()
904 rwlock_.reader_unlock();
908 void RWLock::ReaderLock::acquire()
910 rwlock_.reader_lock();
915 bool RWLock::ReaderLock::try_acquire()
917 locked_ = rwlock_.reader_trylock();
922 void RWLock::ReaderLock::release()
924 rwlock_.reader_unlock();
929 bool RWLock::ReaderLock::locked() const
935 /**** Glib::RWLock::WriterLock *********************************************/
938 RWLock::WriterLock::WriterLock(RWLock& rwlock)
943 rwlock_.writer_lock();
947 RWLock::WriterLock::WriterLock(RWLock& rwlock, NotLock)
954 RWLock::WriterLock::WriterLock(RWLock& rwlock, TryLock)
957 locked_ (rwlock.writer_trylock())
961 RWLock::WriterLock::~WriterLock()
964 rwlock_.writer_unlock();
968 void RWLock::WriterLock::acquire()
970 rwlock_.writer_lock();
975 bool RWLock::WriterLock::try_acquire()
977 locked_ = rwlock_.writer_trylock();
982 void RWLock::WriterLock::release()
984 rwlock_.writer_unlock();
989 bool RWLock::WriterLock::locked() const
995 /**** Glib::StaticPrivate **************************************************/
999 void StaticPrivate<T>::delete_ptr(void* data)
1001 delete static_cast<T*>(data);
1004 template <class T> inline
1005 T* StaticPrivate<T>::get()
1007 return static_cast<T*>(g_static_private_get(&gobject_));
1010 template <class T> inline
1011 void StaticPrivate<T>::set(T* data, typename StaticPrivate<T>::DestroyNotifyFunc notify_func)
1013 g_static_private_set(&gobject_, data, notify_func);
1017 /**** Glib::Private ********************************************************/
1021 void Private<T>::delete_ptr(void* data)
1023 delete static_cast<T*>(data);
1026 template <class T> inline
1027 Private<T>::Private(typename Private<T>::DestructorFunc destructor_func)
1029 gobject_ (g_private_new(destructor_func))
1032 template <class T> inline
1033 T* Private<T>::get()
1035 return static_cast<T*>(g_private_get(gobject_));
1038 template <class T> inline
1039 void Private<T>::set(T* data)
1041 g_private_set(gobject_, data);
1044 #endif /* DOXYGEN_SHOULD_SKIP_THIS */