diff options
author | Murray Cumming <murrayc@murrayc.com> | 2011-11-23 13:42:55 +0100 |
---|---|---|
committer | Murray Cumming <murrayc@murrayc.com> | 2011-11-23 13:42:55 +0100 |
commit | 768123b31049e1164a50eb22af8b4c4b4fd46d72 (patch) | |
tree | e87494f4d8c73a7207b5f971673dfc21f157b627 | |
parent | d7e3bb63fa8841cf1cd06befab3a7a769adff46a (diff) | |
download | glibmm-768123b31049e1164a50eb22af8b4c4b4fd46d72.tar.gz |
Add Glib::Threads::* in threads.h, deprecating everything in thread.h
* glib/src/filelist.am:
* glib/src/thread.[hg|ccg]: Deprecate the whole file, adding
deprecation doxygen comments to all API.
* glib/src/threads.[hg|ccg]: A new Threads namespace containing
equivalents for everything in thread.h, implemented using
only non-deprecated glib API. This was necessary because we had
to break the ABI to do this.
* glib/glibmm.h: Include threads.h
* glib/glibmm/main.[h|cc]: Added a wait() method overload that
takes the new types, deprecating the existing wait() method.
* examples/network/resolver.cc:
* examples/network/socket-client.cc:
* examples/network/socket-server.cc:
* examples/thread/dispatcher.cc:
* examples/thread/dispatcher2.cc:
* examples/thread/thread.cc:
* examples/thread/threadpool.cc:
* glib/glibmm/dispatcher.cc:
* glib/glibmm/exceptionhandler.cc:
* glib/glibmm/threadpool.[h|cc]: Use the new Glib::Threads::* types
instead of thread.h.
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | examples/network/resolver.cc | 4 | ||||
-rw-r--r-- | examples/network/socket-client.cc | 2 | ||||
-rw-r--r-- | examples/network/socket-server.cc | 2 | ||||
-rw-r--r-- | examples/thread/dispatcher.cc | 4 | ||||
-rw-r--r-- | examples/thread/dispatcher2.cc | 12 | ||||
-rw-r--r-- | examples/thread/thread.cc | 16 | ||||
-rw-r--r-- | examples/thread/threadpool.cc | 6 | ||||
-rw-r--r-- | glib/glibmm.h | 2 | ||||
-rw-r--r-- | glib/glibmm/dispatcher.cc | 7 | ||||
-rw-r--r-- | glib/glibmm/exceptionhandler.cc | 4 | ||||
-rw-r--r-- | glib/glibmm/main.cc | 15 | ||||
-rw-r--r-- | glib/glibmm/main.h | 22 | ||||
-rw-r--r-- | glib/glibmm/threadpool.cc | 9 | ||||
-rw-r--r-- | glib/glibmm/threadpool.h | 2 | ||||
-rw-r--r-- | glib/glibmm/utility.h | 6 | ||||
-rw-r--r-- | glib/src/filelist.am | 2 | ||||
-rw-r--r-- | glib/src/thread.ccg | 12 | ||||
-rw-r--r-- | glib/src/thread.hg | 77 | ||||
-rw-r--r-- | glib/src/threads.ccg | 237 | ||||
-rw-r--r-- | glib/src/threads.hg | 763 |
21 files changed, 1163 insertions, 69 deletions
@@ -1,5 +1,33 @@ 2011-11-23 Murray Cumming <murrayc@murrayc.com> + Add Glib::Threads::* in threads.h, deprecating everything in thread.h + + * glib/src/filelist.am: + * glib/src/thread.[hg|ccg]: Deprecate the whole file, adding + deprecation doxygen comments to all API. + * glib/src/threads.[hg|ccg]: A new Threads namespace containing + equivalents for everything in thread.h, implemented using + only non-deprecated glib API. This was necessary because we had + to break the ABI to do this. + * glib/glibmm.h: Include threads.h + + * glib/glibmm/main.[h|cc]: Added a wait() method overload that + takes the new types, deprecating the existing wait() method. + + * examples/network/resolver.cc: + * examples/network/socket-client.cc: + * examples/network/socket-server.cc: + * examples/thread/dispatcher.cc: + * examples/thread/dispatcher2.cc: + * examples/thread/thread.cc: + * examples/thread/threadpool.cc: + * glib/glibmm/dispatcher.cc: + * glib/glibmm/exceptionhandler.cc: + * glib/glibmm/threadpool.[h|cc]: Use the new Glib::Threads::* types + instead of thread.h. + +2011-11-23 Murray Cumming <murrayc@murrayc.com> + Avoid a deprecation warning in implelementation of deprecated API. * glib/glibmm/main.cc: Define GLIB_DISABLE_DEPRECATION_WARNINGS diff --git a/examples/network/resolver.cc b/examples/network/resolver.cc index 7ce8cef9..1d6303ca 100644 --- a/examples/network/resolver.cc +++ b/examples/network/resolver.cc @@ -212,9 +212,11 @@ start_threaded_lookups (char **argv, int argc) int i; for (i = 0; i < argc; i++) - Glib::Thread::create (sigc::bind (sigc::ptr_fun (lookup_thread), + { + Glib::Threads::Thread::create (sigc::bind (sigc::ptr_fun (lookup_thread), argv[i]), false); + } } static void diff --git a/examples/network/socket-client.cc b/examples/network/socket-client.cc index e6c5ae15..b1f08715 100644 --- a/examples/network/socket-client.cc +++ b/examples/network/socket-client.cc @@ -128,7 +128,7 @@ main (int argc, if (cancel_timeout) { cancellable = Gio::Cancellable::create (); - Glib::Thread::create (sigc::bind (sigc::ptr_fun (cancel_thread), cancellable), false); + Glib::Threads::Thread::create (sigc::bind (sigc::ptr_fun (cancel_thread), cancellable), false); } loop = Glib::MainLoop::create (); diff --git a/examples/network/socket-server.cc b/examples/network/socket-server.cc index bc2822b1..d99a176a 100644 --- a/examples/network/socket-server.cc +++ b/examples/network/socket-server.cc @@ -124,7 +124,7 @@ main (int argc, if (cancel_timeout) { cancellable = Gio::Cancellable::create (); - Glib::Thread::create (sigc::bind (sigc::ptr_fun (cancel_thread), cancellable), false); + Glib::Threads::Thread::create (sigc::bind (sigc::ptr_fun (cancel_thread), cancellable), false); } loop = Glib::MainLoop::create (); diff --git a/examples/thread/dispatcher.cc b/examples/thread/dispatcher.cc index 01906ab9..7725b3ee 100644 --- a/examples/thread/dispatcher.cc +++ b/examples/thread/dispatcher.cc @@ -45,7 +45,7 @@ private: // Note that the thread does not write to the member data at all. It only // reads signal_increment_, which is only written to before the thread is // lauched. Therefore, no locking is required. - Glib::Thread* thread_; + Glib::Threads::Thread* thread_; int id_; unsigned int progress_; Glib::Dispatcher signal_increment_; @@ -102,7 +102,7 @@ int ThreadProgress::id() const void ThreadProgress::launch() { // Create a joinable thread. - thread_ = Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), true); + thread_ = Glib::Threads::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), true); } void ThreadProgress::join() diff --git a/examples/thread/dispatcher2.cc b/examples/thread/dispatcher2.cc index 2f837b31..63b06d33 100644 --- a/examples/thread/dispatcher2.cc +++ b/examples/thread/dispatcher2.cc @@ -47,9 +47,9 @@ private: Glib::Dispatcher signal_increment_; Glib::Dispatcher* signal_finished_ptr_; - Glib::Mutex startup_mutex_; - Glib::Cond startup_cond_; - Glib::Thread* thread_; + Glib::Threads::Mutex startup_mutex_; + Glib::Threads::Cond startup_cond_; + Glib::Threads::Thread* thread_; static type_signal_end signal_end_; @@ -93,10 +93,10 @@ void ThreadTimer::launch() // order to access the Dispatcher object instantiated by the 2nd thread. // So, let's do some kind of hand-shake using a mutex and a condition // variable. - Glib::Mutex::Lock lock (startup_mutex_); + Glib::Threads::Mutex::Lock lock (startup_mutex_); // Create a joinable thread -- it needs to be joined, otherwise it's a memory leak. - thread_ = Glib::Thread::create( + thread_ = Glib::Threads::Thread::create( sigc::mem_fun(*this, &ThreadTimer::thread_function), true); // Wait for the 2nd thread's startup notification. @@ -167,7 +167,7 @@ void ThreadTimer::thread_function() // We need to lock while creating the Dispatcher instance, // in order to ensure memory visibility. - Glib::Mutex::Lock lock (startup_mutex_); + Glib::Threads::Mutex::Lock lock (startup_mutex_); // create a new dispatcher, that is connected to the newly // created MainContext diff --git a/examples/thread/thread.cc b/examples/thread/thread.cc index 06c25f8c..581bdf5c 100644 --- a/examples/thread/thread.cc +++ b/examples/thread/thread.cc @@ -1,7 +1,7 @@ #include <iostream> #include <queue> -#include <glibmm/thread.h> +#include <glibmm/threads.h> #include <glibmm/random.h> #include <glibmm/timer.h> #include <glibmm/init.h> @@ -19,9 +19,9 @@ public: void consumer(); private: - Glib::Mutex mutex_; - Glib::Cond cond_push_; - Glib::Cond cond_pop_; + Glib::Threads::Mutex mutex_; + Glib::Threads::Cond cond_push_; + Glib::Threads::Cond cond_pop_; std::queue<int> queue_; }; @@ -39,7 +39,7 @@ void MessageQueue::producer() for(int i = 0; i < 200; ++i) { { - Glib::Mutex::Lock lock (mutex_); + Glib::Threads::Mutex::Lock lock (mutex_); while(queue_.size() >= 64) cond_pop_.wait(mutex_); @@ -65,7 +65,7 @@ void MessageQueue::consumer() for(;;) { { - Glib::Mutex::Lock lock (mutex_); + Glib::Threads::Mutex::Lock lock (mutex_); while(queue_.empty()) cond_push_.wait(mutex_); @@ -97,10 +97,10 @@ int main(int, char**) MessageQueue queue; - Glib::Thread *const producer = Glib::Thread::create( + Glib::Threads::Thread *const producer = Glib::Threads::Thread::create( sigc::mem_fun(queue, &MessageQueue::producer), true); - Glib::Thread *const consumer = Glib::Thread::create( + Glib::Threads::Thread *const consumer = Glib::Threads::Thread::create( sigc::mem_fun(queue, &MessageQueue::consumer), true); producer->join(); diff --git a/examples/thread/threadpool.cc b/examples/thread/threadpool.cc index 6ee38477..632a77af 100644 --- a/examples/thread/threadpool.cc +++ b/examples/thread/threadpool.cc @@ -1,6 +1,6 @@ #include <iostream> -#include <glibmm/thread.h> +#include <glibmm/threads.h> #include <glibmm/random.h> #include <glibmm/threadpool.h> #include <glibmm/timer.h> @@ -9,7 +9,7 @@ namespace { -Glib::Mutex mutex; +Glib::Threads::Mutex mutex; void print_char(char c) { @@ -18,7 +18,7 @@ void print_char(char c) for(int i = 0; i < 100; ++i) { { - Glib::Mutex::Lock lock (mutex); + Glib::Threads::Mutex::Lock lock (mutex); std::cout << c; std::cout.flush(); } diff --git a/glib/glibmm.h b/glib/glibmm.h index 7cc5ad5c..9fb35e8d 100644 --- a/glib/glibmm.h +++ b/glib/glibmm.h @@ -86,6 +86,8 @@ //so we can do an undef trick to still use deprecated API in the header: #include <glibmm/thread.h> +#include <glibmm/threads.h> + #include <glibmm/arrayhandle.h> #include <glibmm/balancedtree.h> #include <glibmm/checksum.h> diff --git a/glib/glibmm/dispatcher.cc b/glib/glibmm/dispatcher.cc index 1be104eb..4640236c 100644 --- a/glib/glibmm/dispatcher.cc +++ b/glib/glibmm/dispatcher.cc @@ -18,7 +18,7 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <glibmm/thread.h> +#include <glibmm/threads.h> #include <glibmm/dispatcher.h> #include <glibmm/exceptionhandler.h> #include <glibmm/fileutils.h> @@ -137,7 +137,7 @@ protected: explicit DispatchNotifier(const Glib::RefPtr<MainContext>& context); private: - static Glib::StaticPrivate<DispatchNotifier> thread_specific_instance_; + static Glib::Threads::Private<DispatchNotifier> thread_specific_instance_; long ref_count_; Glib::RefPtr<MainContext> context_; @@ -161,8 +161,7 @@ private: /**** Glib::DispatchNotifier ***********************************************/ // static -Glib::StaticPrivate<DispatchNotifier> -DispatchNotifier::thread_specific_instance_ = GLIBMM_STATIC_PRIVATE_INIT; +Glib::Threads::Private<DispatchNotifier> DispatchNotifier::thread_specific_instance_; DispatchNotifier::DispatchNotifier(const Glib::RefPtr<MainContext>& context) : diff --git a/glib/glibmm/exceptionhandler.cc b/glib/glibmm/exceptionhandler.cc index 79f1a81c..734da3ef 100644 --- a/glib/glibmm/exceptionhandler.cc +++ b/glib/glibmm/exceptionhandler.cc @@ -20,7 +20,7 @@ */ #include <glibmmconfig.h> -#include <glibmm/thread.h> +#include <glibmm/threads.h> #include <glibmm/error.h> #include <glibmm/exceptionhandler.h> #include <glib.h> @@ -35,7 +35,7 @@ typedef sigc::signal<void> HandlerList; // Each thread has its own list of exception handlers // to avoid thread synchronization problems. -static Glib::StaticPrivate<HandlerList> thread_specific_handler_list = GLIBMM_STATIC_PRIVATE_INIT; +static Glib::Threads::Private<HandlerList> thread_specific_handler_list; static void glibmm_exception_warning(const GError* error) diff --git a/glib/glibmm/main.cc b/glib/glibmm/main.cc index 8bb4500f..eb279c5e 100644 --- a/glib/glibmm/main.cc +++ b/glib/glibmm/main.cc @@ -18,11 +18,15 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <glibmm/thread.h> - #undef G_DISABLE_DEPRECATED //So we can use newly-deprecated API, to preserve our API. #define GLIB_DISABLE_DEPRECATION_WARNINGS 1 +#include <glibmm/threads.h> + +#ifndef GLIBMM_DISABLE_DEPRECATED +#include <glibmm/thread.h> +#endif //GLIBMM_DISABLE_DEPRECATED + #include <glibmm/main.h> #include <glibmm/exceptionhandler.h> #include <glibmm/wrap.h> @@ -492,10 +496,17 @@ bool MainContext::acquire() return g_main_context_acquire(gobj()); } +#ifndef GLIBMM_DISABLE_DEPRECATED bool MainContext::wait(Glib::Cond& cond, Glib::Mutex& mutex) { return g_main_context_wait(gobj(), cond.gobj(), mutex.gobj()); } +#endif //GLIBMM_DISABLE_DEPRECATED + +bool MainContext::wait(Glib::Threads::Cond& cond, Glib::Threads::Mutex& mutex) +{ + return g_main_context_wait(gobj(), cond.gobj(), mutex.gobj()); +} void MainContext::release() { diff --git a/glib/glibmm/main.h b/glib/glibmm/main.h index 6d1cbda9..908b5d1f 100644 --- a/glib/glibmm/main.h +++ b/glib/glibmm/main.h @@ -30,8 +30,16 @@ namespace Glib { +#ifndef GLIBMM_DISABLE_DEPRECATED class Cond; class Mutex; +#endif //GLIBMM_DISABLE_DEPRECATED + +namespace Threads +{ + class Cond; + class Mutex; +} /** @defgroup MainLoop The Main Event Loop * Manages all available sources of events. @@ -353,15 +361,27 @@ public: */ bool acquire(); - +#ifndef GLIBMM_DISABLE_DEPRECATED /** Tries to become the owner of the specified context, as with acquire(). But if another thread is the owner, * atomically drop mutex and wait on cond until that owner releases ownership or until cond is signaled, then try * again (once) to become the owner. * @param cond A condition variable. * @param mutex A mutex, currently held. * @return true if the operation succeeded, and this thread is now the owner of context. + * + * @deprecated Use wait(Glib::Threads::Cond& cond, Glib::Threads::Mutex& mutex) instead. */ bool wait(Glib::Cond& cond, Glib::Mutex& mutex); +#endif //GLIBMM_DISABLE_DEPRECATED + + /** Tries to become the owner of the specified context, as with acquire(). But if another thread is the owner, + * atomically drop mutex and wait on cond until that owner releases ownership or until cond is signaled, then try + * again (once) to become the owner. + * @param cond A condition variable. + * @param mutex A mutex, currently held. + * @return true if the operation succeeded, and this thread is now the owner of context. + */ + bool wait(Glib::Threads::Cond& cond, Glib::Threads::Mutex& mutex); /** Releases ownership of a context previously acquired by this thread with acquire(). If the context was acquired * multiple times, the only release ownership when release() is called as many times as it was acquired. diff --git a/glib/glibmm/threadpool.cc b/glib/glibmm/threadpool.cc index acab296e..9a9af184 100644 --- a/glib/glibmm/threadpool.cc +++ b/glib/glibmm/threadpool.cc @@ -20,6 +20,7 @@ #include <glibmmconfig.h> #include <glibmm/threadpool.h> #include <glibmm/exceptionhandler.h> +#include <glibmm/threads.h> #include <glib.h> #include <list> @@ -39,7 +40,7 @@ public: void lock_and_unlock(); private: - Glib::Mutex mutex_; + Glib::Threads::Mutex mutex_; std::list< sigc::slot<void> > list_; // noncopyable @@ -55,7 +56,7 @@ ThreadPool::SlotList::~SlotList() sigc::slot<void>* ThreadPool::SlotList::push(const sigc::slot<void>& slot) { - Mutex::Lock lock (mutex_); + Threads::Mutex::Lock lock (mutex_); list_.push_back(slot); return &list_.back(); @@ -66,7 +67,7 @@ sigc::slot<void> ThreadPool::SlotList::pop(sigc::slot<void>* slot_ptr) sigc::slot<void> slot; { - Mutex::Lock lock (mutex_); + Threads::Mutex::Lock lock (mutex_); std::list< sigc::slot<void> >::iterator pslot = list_.begin(); while(pslot != list_.end() && slot_ptr != &*pslot) @@ -105,7 +106,7 @@ static void call_thread_entry_slot(void* data, void* user_data) slot(); } - catch(Glib::Thread::Exit&) + catch(Glib::Threads::Thread::Exit&) { // Just exit from the thread. The Thread::Exit exception // is our sane C++ replacement of g_thread_exit(). diff --git a/glib/glibmm/threadpool.h b/glib/glibmm/threadpool.h index 0d632f8b..9cb0f2d2 100644 --- a/glib/glibmm/threadpool.h +++ b/glib/glibmm/threadpool.h @@ -21,7 +21,7 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <glibmm/thread.h> +#include <sigc++/sigc++.h> extern "C" { typedef struct _GThreadPool GThreadPool; } diff --git a/glib/glibmm/utility.h b/glib/glibmm/utility.h index 000e1b08..abb45357 100644 --- a/glib/glibmm/utility.h +++ b/glib/glibmm/utility.h @@ -30,19 +30,21 @@ * GLIBMM_INITIALIZE_STRUCT(Var, Type) is provided. It even avoids creating * a temporary if the compiler is GCC. */ -#if ((__GNUC__ >= 3) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) && !defined(__STRICT_ANSI__) +#if ((__GNUC__ >= 3) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) #define GLIBMM_INITIALIZE_STRUCT(Var, Type) __builtin_memset(&(Var), 0, sizeof(Type)) #else +//TODO: This causes warnings like this: +//"missing initializer for member" #define GLIBMM_INITIALIZE_STRUCT(Var, Type) \ G_STMT_START{ \ Type const temp_initializer__ = { 0, }; \ (Var) = temp_initializer__; \ }G_STMT_END -#endif /* ((__GNUC__ >= 3) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) && !defined(__STRICT_ANSI__) */ +#endif namespace Glib diff --git a/glib/src/filelist.am b/glib/src/filelist.am index fedd32b6..06c6baf9 100644 --- a/glib/src/filelist.am +++ b/glib/src/filelist.am @@ -14,6 +14,7 @@ glibmm_files_defs = \ glib_docs.xml \ glib_docs_override.xml +# Note that all of thread.hg is deprecated glibmm_files_hg = \ balancedtree.hg \ checksum.hg \ @@ -33,6 +34,7 @@ glibmm_files_hg = \ shell.hg \ spawn.hg \ thread.hg \ + threads.hg \ timezone.hg \ unicode.hg \ uriutils.hg \ diff --git a/glib/src/thread.ccg b/glib/src/thread.ccg index bc27592a..e7d6b062 100644 --- a/glib/src/thread.ccg +++ b/glib/src/thread.ccg @@ -21,6 +21,7 @@ #include <glibmm/exceptionhandler.h> #include <glib.h> +_DEPRECATE_IFDEF_START namespace { @@ -59,8 +60,6 @@ static void* call_thread_entry_slot(void* data) namespace Glib { -_DEPRECATE_IFDEF_START - // This was always meant as an internal method. It is no longer called, // and no longer needs to be called. We are keeping it just to avoid // breaking ABI, though hopefully nobody is using it anyway. @@ -71,8 +70,6 @@ void thread_init_impl() Glib::Error::register_init(); } -_DEPRECATE_IFDEF_END - /**** Glib::Thread *********************************************************/ // static @@ -87,7 +84,6 @@ Thread* Thread::create(const sigc::slot<void>& slot, bool /* joinable */) return reinterpret_cast<Thread*>(thread); } -_DEPRECATE_IFDEF_START // static Thread* Thread::create(const sigc::slot<void>& slot, unsigned long stack_size, bool joinable, bool bound, ThreadPriority priority) @@ -109,7 +105,6 @@ Thread* Thread::create(const sigc::slot<void>& slot, unsigned long stack_size, return reinterpret_cast<Thread*>(thread); } -_DEPRECATE_IFDEF_END // static Thread* Thread::self() @@ -122,8 +117,6 @@ void Thread::join() g_thread_join(&gobject_); } -_DEPRECATE_IFDEF_START - bool Thread::joinable() const { return true; //An appropriate result now that this is deprecated because all threads are now joinable. @@ -155,8 +148,6 @@ bool thread_supported() return (g_thread_supported() != 0); } -_DEPRECATE_IFDEF_END - // static void Thread::yield() @@ -387,3 +378,4 @@ bool Cond::timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time) } // namespace Glib +_DEPRECATE_IFDEF_END diff --git a/glib/src/thread.hg b/glib/src/thread.hg index 054667a2..a007deca 100644 --- a/glib/src/thread.hg +++ b/glib/src/thread.hg @@ -19,6 +19,8 @@ _DEFS(glibmm,glib) #include <glibmmconfig.h> +_DEPRECATE_IFDEF_START + // We use GThreadFunctions in the (deprecated) API, so we must temporarily undef G_DISABLE_DEPRECATED. // Temporarily undef G_DISABLE_DEPRECATED, redefining it later if appropriate. #if defined(G_DISABLE_DEPRECATED) && !defined(GLIBMM_G_DISABLE_DEPRECATED_UNDEFED) @@ -63,27 +65,30 @@ enum { THREAD_PRIORITY_NORMAL = GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL } /** Initializer macro for Glib::StaticRecMutex. * @relates Glib::StaticRecMutex * @hideinitializer + * + * @deprecated Glib::StaticRecMutex is deprecated in favour of Glib::Threads::RecMutex, which can be used statically. */ #define GLIBMM_STATIC_REC_MUTEX_INIT { G_STATIC_REC_MUTEX_INIT } /** Initializer macro for Glib::StaticRWLock. * @relates Glib::StaticRWLock * @hideinitializer + * + * @deprecated Glib::StaticRWLock is deprecated in favour of Glib::Threads::RWLock, which can be used statically. */ #define GLIBMM_STATIC_RW_LOCK_INIT { G_STATIC_RW_LOCK_INIT } /** Initializer macro for Glib::StaticPrivate. * @relates Glib::StaticPrivate * @hideinitializer + * + * @deprecated Glib::StaticPrivate is deprecated in favour of Glib::Threads::Private, which can be used statically. */ #define GLIBMM_STATIC_PRIVATE_INIT { G_STATIC_PRIVATE_INIT } namespace Glib { - -_DEPRECATE_IFDEF_START - /** @deprecated Thread priorities no longer have any effect. */ _WRAP_ENUM(ThreadPriority, GThreadPriority, NO_GTYPE) @@ -112,15 +117,14 @@ void thread_init(GThreadFunctions* vtable = 0); */ bool thread_supported(); -_DEPRECATE_IFDEF_END - -/** @defgroup Threads Threads - * Thread abstraction; including threads, different mutexes, - * conditions and thread private data. - * @{ +/** + * @deprecated Use Glib::Threads::NotLock instead. */ - enum NotLock { NOT_LOCK }; + +/** + * @deprecated Use Glib::Threads::TryLock instead. + */ enum TryLock { TRY_LOCK }; class Mutex; @@ -132,6 +136,7 @@ struct StaticRWLock; /** Exception class for thread-related errors. + * @deprecated Use Glib::Threads::ThreadError instead. */ _WRAP_GERROR(ThreadError, GThreadError, G_THREAD_ERROR, NO_GTYPE) @@ -152,6 +157,8 @@ _WRAP_GERROR(ThreadError, GThreadError, G_THREAD_ERROR, NO_GTYPE) * @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. + * + * @deprecated Use Glib::Threads::Thread instead. */ class Thread { @@ -192,7 +199,6 @@ public: */ void join(); -_DEPRECATE_IFDEF_START //See http://bugzilla.gnome.org/show_bug.cgi?id=512348 about the sigc::trackable issue. /** 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 @@ -268,8 +274,6 @@ _DEPRECATE_IFDEF_START */ ThreadPriority get_priority() const; -_DEPRECATE_IFDEF_END - /** 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. @@ -299,15 +303,20 @@ private: * 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 <tt>catch(...)</tt> somewhere in your code. + * + * @deprecated Use Glib::Threads::Thread::Exit instead. */ class Thread::Exit {}; -/** @relates Glib::Thread */ -Thread* wrap(GThread* gobject); +//TODO: Make sure that Glib::wrap() uses Glib::Threads::wrap() instead. -_DEPRECATE_IFDEF_START +/** @relates Glib::Thread + * + * @deprecated Use Glib::Threads::wrap(GThread*) instead. + */ +Thread* wrap(GThread* gobject); struct StaticMutex; @@ -321,6 +330,8 @@ struct StaticMutex; * 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. + * + * @deprecated Use Glib::Threads::Mutex instead, which can be used statically. */ struct StaticMutex { @@ -341,11 +352,11 @@ struct StaticMutex /** Initializer macro for Glib::StaticMutex. * @relates Glib::StaticMutex * @hideinitializer + * + * @deprecated Glib::StaticMutex is deprecated in favour of Glib::Threads::Mutex, which can be used statically. */ #define GLIBMM_STATIC_MUTEX_INIT { G_STATIC_MUTEX_INIT } -_DEPRECATE_IFDEF_END - /** 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 -- @@ -354,6 +365,8 @@ _DEPRECATE_IFDEF_END * @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. + * + * @deprecated Use Glib::Threads::Mutex instead. */ class Mutex { @@ -407,6 +420,8 @@ private: * only exception safe but also much less error-prone. You could even * <tt>return</tt> while still holding the lock and it will be released * properly. + * + * @deprecated Use Glib::Threads::Mutex::Lock instead. */ class Mutex::Lock { @@ -440,6 +455,8 @@ private: * 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. + * + * @deprecated Use Glib::Threads::RecMutex instead, which can be used statically. */ struct StaticRecMutex { @@ -460,6 +477,10 @@ struct StaticRecMutex #endif }; +/** + * + * @deprecated Use Glib::Threads::RecMutex instead. + */ class RecMutex : public StaticRecMutex { public: @@ -475,6 +496,8 @@ private: }; /** Utility class for exception-safe locking of recursive mutexes. + * + * @deprecated Use Glib::Threads::RecMutex instead. */ class RecMutex::Lock { @@ -508,6 +531,8 @@ private: * 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. + * + * @deprecated Use Glib::Threads::RWLock instead, which can be used statically. */ struct StaticRWLock { @@ -529,6 +554,10 @@ struct StaticRWLock #endif }; +/** + * + * @deprecated Use Glib::Threads::RWLock instead. + */ class RWLock : public StaticRWLock { public: @@ -545,6 +574,8 @@ private: }; /** Utility class for exception-safe locking of read/write locks. + * + * @deprecated Use Glib::Threads::RWLock::ReaderLock instead. */ class RWLock::ReaderLock { @@ -569,6 +600,8 @@ private: }; /** Utility class for exception-safe locking of read/write locks. + * + * @deprecated Use Glib::Threads::RWLock::WriterLock instead. */ class RWLock::WriterLock { @@ -623,7 +656,9 @@ private: * return data; * } * @endcode -*/ + * + * @deprecated Use Glib::Threads::Cond instead. + */ class Cond { public: @@ -736,12 +771,10 @@ private: /* inline implementation */ /***************************************************************************/ -_DEPRECATE_IFDEF_START // internal /** @deprecated This was always for internal glibmm use and is now unecessary even inside glibmm. */ void thread_init_impl(); -_DEPRECATE_IFDEF_END /**** Glib::Mutex::Lock ****************************************************/ @@ -1038,3 +1071,5 @@ void Private<T>::set(T* data) _IGNORE(g_iconv) } // namespace Glib + +_DEPRECATE_IFDEF_END diff --git a/glib/src/threads.ccg b/glib/src/threads.ccg new file mode 100644 index 00000000..2431b0c0 --- /dev/null +++ b/glib/src/threads.ccg @@ -0,0 +1,237 @@ +// -*- c++ -*- +/* $Id: thread.ccg,v 1.9 2006/05/12 08:08:44 murrayc Exp $ */ + +/* 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <glibmm/exceptionhandler.h> +#include <glib.h> + + +namespace +{ + +extern "C" +{ + +static void* call_thread_entry_slot(void* data) +{ + sigc::slot_base *const slot = reinterpret_cast<sigc::slot_base*>(data); + + try + { + // Recreate the specific slot, and drop the reference obtained by create(). + (*static_cast<sigc::slot<void>*>(slot))(); + } + catch(Glib::Thread::Exit&) + { + // Just exit from the thread. The Thread::Exit exception + // is our sane C++ replacement of g_thread_exit(). + } + catch(...) + { + Glib::exception_handlers_invoke(); + } + + delete slot; + return 0; +} + +} //extern "C" + +} // anonymous namespace + + +namespace Glib +{ + +namespace Threads +{ + +/**** Glib::Thread *********************************************************/ + +// static +Thread* Thread::create(const sigc::slot<void>& slot, bool /* joinable */) +{ + // Make a copy of slot on the heap + sigc::slot_base *const slot_copy = new sigc::slot<void>(slot); + + GThread *const thread = g_thread_new(NULL, + &call_thread_entry_slot, slot_copy); + + return reinterpret_cast<Thread*>(thread); +} + +// static +Thread* Thread::self() +{ + return reinterpret_cast<Thread*>(g_thread_self()); +} + +void Thread::join() +{ + g_thread_join(&gobject_); +} + +// static +void Thread::yield() +{ + g_thread_yield(); +} + + +Thread* wrap(GThread* gobject) +{ + return reinterpret_cast<Thread*>(gobject); +} + + +/**** Glib::Mutex **********************************************************/ + +Mutex::Mutex() +{ + g_mutex_init(&gobject_); +} + +Mutex::~Mutex() +{ + g_mutex_clear(&gobject_); +} + +void Mutex::lock() +{ + g_mutex_lock(&gobject_); +} + +bool Mutex::trylock() +{ + return g_mutex_trylock(&gobject_); +} + +void Mutex::unlock() +{ + g_mutex_unlock(&gobject_); +} + +/**** Glib::RecMutex *******************************************************/ + +RecMutex::RecMutex() +{ + g_rec_mutex_init(&gobject_); +} + +RecMutex::~RecMutex() +{ + g_rec_mutex_clear(&gobject_); +} + +void RecMutex::lock() +{ + g_rec_mutex_lock(&gobject_); +} + +bool RecMutex::trylock() +{ + return g_rec_mutex_trylock(&gobject_); +} + +void RecMutex::unlock() +{ + g_rec_mutex_unlock(&gobject_); +} + +/**** Glib::RWLock ***************************************************/ + +void RWLock::reader_lock() +{ + g_rw_lock_reader_lock(&gobject_); +} + +bool RWLock::reader_trylock() +{ + return g_rw_lock_reader_trylock(&gobject_); +} + +void RWLock::reader_unlock() +{ + g_rw_lock_reader_unlock(&gobject_); +} + +void RWLock::writer_lock() +{ + g_rw_lock_writer_lock(&gobject_); +} + +bool RWLock::writer_trylock() +{ + return g_rw_lock_writer_trylock(&gobject_); +} + +void RWLock::writer_unlock() +{ + g_rw_lock_writer_unlock(&gobject_); +} + +/**** Glib::RWLock *********************************************************/ + +RWLock::RWLock() +{ + g_rw_lock_init(&gobject_); +} + +RWLock::~RWLock() +{ + g_rw_lock_clear(&gobject_); +} + + +/**** Glib::Cond ***********************************************************/ + +Cond::Cond() +{ + g_cond_init(&gobject_); +} + +Cond::~Cond() +{ + g_cond_clear(&gobject_); +} + +void Cond::signal() +{ + g_cond_signal(&gobject_); +} + +void Cond::broadcast() +{ + g_cond_broadcast(&gobject_); +} + +void Cond::wait(Mutex& mutex) +{ + g_cond_wait(&gobject_, mutex.gobj()); +} + +bool Cond::wait_until(Mutex& mutex, gint64 end_time) +{ + return g_cond_wait_until(&gobject_, mutex.gobj(), end_time); +} + +} // namespace Threads + +} // namespace Glib + diff --git a/glib/src/threads.hg b/glib/src/threads.hg new file mode 100644 index 00000000..633189fe --- /dev/null +++ b/glib/src/threads.hg @@ -0,0 +1,763 @@ +/* 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 Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +_DEFS(glibmm,glib) + +#include <glibmmconfig.h> + +#include <glib.h> + +#include <glibmm/error.h> +#include <sigc++/sigc++.h> + +#include <cstddef> + +namespace Glib +{ + +namespace Threads +{ + +/** @defgroup Threads Threads + * Thread abstraction; including threads, different mutexes, + * conditions and thread private data. + * @{ + */ + +enum NotLock { NOT_LOCK }; +enum TryLock { TRY_LOCK }; + +class Mutex; +class RecMutex; +class RWLock; + +/** Exception class for thread-related errors. + */ +_WRAP_GERROR(ThreadError, GThreadError, G_THREAD_ERROR, NO_GTYPE) + + +/** 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; + + //See http://bugzilla.gnome.org/show_bug.cgi?id=512348 about the sigc::trackable issue. + /** Creates a new thread with the priority <tt>THREAD_PRIORITY_NORMAL</tt>. + * 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. + * + * Because sigc::trackable is not thread safe, if the slot represents a + * non-static class method (that is, it is created by sigc::mem_fun()), the + * class concerned should not derive from sigc::trackable. + * + * @param slot A slot to execute in the new thread. + * @param joinable This parameter is now ignored because Threads are now always joinable. + * @return The new Thread* on success. + * @throw Glib::ThreadError + */ + static Thread* create(const sigc::slot<void>& slot, bool joinable = true); + + /** Returns the Thread* corresponding to the calling thread. + * @return The current thread. + */ + static Thread* self(); + + /** 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 <tt>joinable = true</tt>. + */ + void join(); + + /** 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 <tt>catch(...)</tt> somewhere in your code. + */ +class Thread::Exit +{}; + +/** @relates Glib::Thread */ +Thread* wrap(GThread* gobject); + +/** 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 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 + * <tt>return</tt> 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&); +}; + +//TODO: Docuemenation +class RecMutex +{ +public: + class Lock; + + RecMutex(); + ~RecMutex(); + + void lock(); + bool trylock(); + void unlock(); + + GRecMutex* gobj() { return &gobject_; } + +private: + // noncopyable + RecMutex(const RecMutex&); + RecMutex& operator=(const RecMutex&); + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + // Must be public to allow initialization at compile time. + GRecMutex gobject_; +#endif +}; + +/** 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&); +}; + + +//TODO: Documentation +class RWLock +{ +public: + class ReaderLock; + class WriterLock; + + RWLock(); + ~RWLock(); + + void reader_lock(); + bool reader_trylock(); + void reader_unlock(); + + void writer_lock(); + bool writer_trylock(); + void writer_unlock(); + + GRWLock* gobj() { return &gobject_; } + +private: + // noncopyable + RWLock(const RWLock&); + RWLock& operator=(const RWLock&); + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + // Must be public to allow initialization at compile time. + GRWLock gobject_; +#endif +}; + +/** 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 = 0; + * + * void push_data(void* data) + * { + * Glib::Mutex::Lock lock (data_mutex); + * + * current_data = data; + * data_cond.signal(); + * } + * + * void* pop_data() + * { + * Glib::Mutex::Lock lock (data_mutex); + * + * while (!current_data) + * data_cond.wait(data_mutex); + * + * void *const data = current_data; + * current_data = 0; + * + * 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. + * + */ + 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. + */ + 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. + * + * @param mutex a @a Mutex that is currently locked. + * + * @note It is important to use the @a wait() and @a wait_until() 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. + * + * @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 wait_until() 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 wait_until(Mutex& mutex, gint64 end_time); + + GCond* gobj() { return &gobject_; } + +private: + GCond gobject_; + + // noncopyable + Cond(const Cond&); + Cond& operator=(const Cond&); +}; + +template <class T> +class Private +{ +public: + typedef void (*DestructorFunc) (void*); + + static void delete_ptr(void* data); + + explicit inline Private(DestructorFunc destructor_func = &Private<T>::delete_ptr); + inline T* get(); + inline void set(T* data); + + GPrivate* gobj() { return gobject_; } + +private: + GPrivate gobject_; + + // noncopyable + Private(const Private<T>&); + Private<T>& operator=(const Private<T>&); +}; + +/** @} group Threads */ + +/*! A glibmm thread example. + * @example thread/thread.cc + */ + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +/***************************************************************************/ +/* inline implementation */ +/***************************************************************************/ + + +/**** 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::Private ********************************************************/ + +// static +template <class T> +void Private<T>::delete_ptr(void* data) +{ + delete static_cast<T*>(data); +} + +template <class T> inline +Private<T>::Private(typename Private<T>::DestructorFunc destructor_func) +{ + //TODO: This causes this warning: + //extended initializer lists only available with -std=c++0x or -std=gnu++0x + //See glib bug: https://bugzilla.gnome.org/show_bug.cgi?id=664618 + //We can work around this by building like so: + //./configure --prefix=/opt/gnome30 'CXXFLAGS=-std=c++0x' + gobject_ = G_PRIVATE_INIT(destructor_func); +} + +template <class T> inline +T* Private<T>::get() +{ + return static_cast<T*>(g_private_get(&gobject_)); +} + +template <class T> inline +void Private<T>::set(T* data) +{ + g_private_set(&gobject_, data); +} + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +// For some reason gmmproc thinks that g_iconv should be wrapped here. +_IGNORE(g_iconv) + +} //namespace Threads + +} // namespace Glib |