Blob Blame History Raw
// Generated by gmmproc 2.54.1 -- DO NOT MODIFY!
#ifndef _GLIBMM_THREAD_H
#define _GLIBMM_THREAD_H

#include <glibmmconfig.h>

#ifndef GLIBMM_DISABLE_DEPRECATED


/* 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, see <http://www.gnu.org/licenses/>.
 */


 // This whole file is deprecated.

 
// 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)
//Stop the deprecation ifdef guards around the API declarations:
#undef G_DISABLE_DEPRECATED
#define GLIBMM_G_DISABLE_DEPRECATED_UNDEFED 1
#endif

#include <glib.h>

// Redefine G_DISABLE_DEPRECATED if it was defined before we temporarily undefed it:
#if defined(GLIBMM_G_DISABLE_DEPRECATED_UNDEFED)
#define G_DISABLE_DEPRECATED 1
#undef GLIBMM_G_DISABLE_DEPRECATED_UNDEFED
#endif


#include <glibmm/error.h>
#include <glibmm/timeval.h>
#include <sigc++/sigc++.h>

#include <cstddef>

/* Shadow THREAD_PRIORITY_NORMAL macro (from winbase.h).
 */
#if defined(THREAD_PRIORITY_NORMAL) && !defined(GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL)
enum { GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL = THREAD_PRIORITY_NORMAL };
#undef THREAD_PRIORITY_NORMAL
enum { THREAD_PRIORITY_NORMAL = GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL };
#define THREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
#define GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL 1
#endif


/** Initializer macro for Glib::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
{

/** @addtogroup glibmmEnums glibmm Enums and Flags */

/**  @deprecated Thread priorities no longer have any effect.
 *  @var ThreadPriority THREAD_PRIORITY_LOW
 * A priority lower than normal.
 * 
 *  @var ThreadPriority THREAD_PRIORITY_NORMAL
 * The default priority.
 * 
 *  @var ThreadPriority THREAD_PRIORITY_HIGH
 * A priority higher than normal.
 * 
 *  @var ThreadPriority THREAD_PRIORITY_URGENT
 * The highest priority.
 * 
 *  @enum ThreadPriority
 * 
 * Thread priorities.
 * 
 * Deprecated:2.32: Thread priorities no longer have any effect.
 *
 * @ingroup glibmmEnums
 */
enum ThreadPriority
{
  THREAD_PRIORITY_LOW,
  THREAD_PRIORITY_NORMAL,
  THREAD_PRIORITY_HIGH,
  THREAD_PRIORITY_URGENT
};


/*! @var ThreadPriority THREAD_PRIORITY_LOW
 * A priority lower than normal.
 */
/*! @var ThreadPriority THREAD_PRIORITY_NORMAL
 * The default priority.
 */
/*! @var ThreadPriority THREAD_PRIORITY_HIGH
 * A priority higher than normal.
 */
/*! @var ThreadPriority THREAD_PRIORITY_URGENT
 * The highest priority.
 */

/** Initializes the GLib thread system.
 * @deprecated Calling thread_init() is no longer necessary and no longer has any effect.
 */
void thread_init(GThreadFunctions* vtable = nullptr);

/** Returns whether the thread system is initialized.
 * @return @c true, if the thread system is initialized.
 * @deprecated This is no longer useful, because the thread system is always initialized.
 */
bool thread_supported();

/**
 * @deprecated Use Glib::Threads::NotLock instead.
 */
enum NotLock { NOT_LOCK };

/**
 * @deprecated Use Glib::Threads::TryLock instead.
 */
enum TryLock { TRY_LOCK };

class Mutex;
class RecMutex;
class RWLock;

struct StaticRecMutex;
struct StaticRWLock;


/**  %Exception class for thread-related errors.
 * @deprecated Use Glib::Threads::ThreadError instead.
 */
class ThreadError : public Glib::Error
{
public:
  /**  @var Code AGAIN
   * A thread couldn't be created due to resource
   * shortage. Try again later.
   * 
   *  @enum Code
   * 
   * Possible errors of thread related functions.
   */
  enum Code
  {
    AGAIN
  };

  ThreadError(Code error_code, const Glib::ustring& error_message);
  explicit ThreadError(GError* gobject);
  Code code() const;

#ifndef DOXYGEN_SHOULD_SKIP_THIS
private:

  static void throw_func(GError* gobject);

  friend void wrap_init(); // uses throw_func()

  #endif //DOXYGEN_SHOULD_SKIP_THIS
};


/** 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.
 *
 * @deprecated Use Glib::Threads::Thread instead.
 */
class Thread
{
public:

  Thread(const Thread&) = delete;
  Thread& operator=(const Thread&) = delete;

  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&nbsp;=&nbsp;true</tt>.
   */
  void join();

  //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
   * @a stack_size is <tt>0</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.
   * If @a bound is @c true, this thread will be scheduled in the system scope,
   * otherwise the implementation is free to do scheduling in the process
   * scope.  The first variant is more expensive resource-wise, but generally
   * faster.  On some systems (e.g. Linux) all threads are bound.
   *
   * The new thread executes the function or method @a slot points to.  You can
   * pass additional arguments using sigc::bind().  If the thread was created
   * successfully, it is returned.
   *
   * 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.
   *
   * @note It is not guaranteed, that threads with different priorities really
   * behave accordingly.  On some systems (e.g. Linux) only root can increase
   * priorities.  On other systems (e.g. Solaris) there doesn't seem to be
   * different scheduling for different priorities.  All in all try to avoid
   * being dependent on priorities.  Use <tt>Glib::THREAD_PRIORITY_NORMAL</tt>
   * here as a default.
   *
   * @note Only use the extended
   * create(const sigc::slot<void>&, unsigned long, bool, bool, ThreadPriority)
   * function, when you really can't use the simple
   * create(const sigc::slot<void>&, bool)
   * instead.  The latter overload does not take @a stack_size, @a bound and
   * @a priority as arguments, as they should only be used for cases, where
   * it is inevitable.
   *
   * @param slot A slot to execute in the new thread.
   * @param stack_size A stack size for the new thread, or <tt>0</tt>.
   * @param joinable Should this thread be joinable?
   * @param bound Should this thread be bound to a system thread?
   * @param priority A priority for the thread.
   * @return The new Thread* on success.
   * @throw Glib::ThreadError
   *
   * @deprecated Use the simpler create() method instead, because all Threads
   * are now joinable, and bounds and priority parameters now have no effect.
   */
  static Thread* create(const sigc::slot<void>& slot, unsigned long stack_size,
                        bool joinable, bool bound, ThreadPriority priority);

  /** Returns whether the thread is joinable.
   * @return Whether the thread is joinable.
   *
   * @deprecated All threads are now joinable.
   */
  bool joinable() const;

  /** Changes the priority of the thread to @a priority.
   * @note It is not guaranteed, that threads with different priorities really
   * behave accordingly.  On some systems (e.g. Linux) only @c root can
   * increase priorities.  On other systems (e.g. Solaris) there doesn't seem
   * to be different scheduling for different priorities.  All in all try to
   * avoid being dependent on priorities.
   * @param priority A new priority for the thread.
   *
   * @deprecated Thread priorities no longer have any effect.
   */
  void set_priority(ThreadPriority priority);

  /** Returns the priority of the thread.
   * @return The thread's priority.
   *
   * @deprecated Thread priorities no longer have any effect.
   */
  ThreadPriority get_priority() const;

  /** Gives way to other threads waiting to be scheduled.
   * This function is often used as a method to make busy wait less evil.  But
   * in most cases, you will encounter, there are better methods to do that.
   * So in general you shouldn't use this function.
   */
  static void yield();

  GThread*       gobj()       { return &gobject_; }
  const GThread* gobj() const { return &gobject_; }

private:
  GThread gobject_;

  // Glib::Thread can neither be constructed nor deleted.
  Thread();
  void operator delete(void*, std::size_t);
};

/** %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.
 *
 * @deprecated Use Glib::Threads::Thread::Exit instead.
 */
class Thread::Exit
{};


//TODO: Make sure that Glib::wrap() uses Glib::Threads::wrap() instead.

/** @relates Glib::Thread
 *
 * @deprecated Use Glib::Threads::wrap(GThread*) instead.
 */
Thread* wrap(GThread* gobject);

struct StaticMutex;

/** Like Glib::Mutex, but can be defined at compile time.
 * Use @c GLIBMM_STATIC_MUTEX_INIT to initialize a StaticMutex:
 * @code
 * Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
 * @endcode
 *
 * A StaticMutex can be used without calling Glib::thread_init(), it will
 * silently do nothing then.  That will also work when using the implicit
 * conversion to Mutex&, thus you can safely use Mutex::Lock with a
 * StaticMutex.
 *
 * @deprecated Use Glib::Threads::Mutex instead, which can be used statically.
 */
struct StaticMutex
{
  void lock();
  bool trylock();
  void unlock();

  operator Mutex&();

  GStaticMutex* gobj() { return &gobject_; }

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  // Must be public to allow initialization at compile time.
  GStaticMutex gobject_;
#endif
};

/** 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 }

/** 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&nbsp;--
 * 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.
 *
 * @deprecated Use Glib::Threads::Mutex instead.
 */
class Mutex
{
public:
  class Lock;

  Mutex();

  Mutex(const Mutex&) = delete;
  Mutex& operator=(const Mutex&) = delete;

  ~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_;
};

/** 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.
 *
 * @deprecated Use Glib::Threads::Mutex::Lock instead.
 */
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_;


};


/** Like Glib::RecMutex, but can be defined at compile time.
 * Use @c GLIBMM_STATIC_REC_MUTEX_INIT to initialize a StaticRecMutex:
 * @code
 * Glib::StaticRecMutex mutex = GLIBMM_STATIC_REC_MUTEX_INIT;
 * @endcode
 * A StaticRecMutex can be used without calling Glib::thread_init(), it will
 * silently do nothing then.  That will also work when using the implicit
 * conversion to RecMutex&, thus you can safely use RecMutex::Lock with a
 * StaticRecMutex.
 *
 * @deprecated Use Glib::Threads::RecMutex instead, which can be used statically.
 */
struct StaticRecMutex
{
  void lock();
  bool trylock();
  void unlock();

  void lock_full(unsigned int depth);
  unsigned int unlock_full();

  operator RecMutex&();

  GStaticRecMutex* gobj() { return &gobject_; }

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  // Must be public to allow initialization at compile time.
  GStaticRecMutex gobject_;
#endif
};

/**
 *
 * @deprecated Use Glib::Threads::RecMutex instead.
 */
class RecMutex : public StaticRecMutex
{
public:
  class Lock;

  RecMutex();
  ~RecMutex();

private:
  // noncopyable
  RecMutex(const RecMutex&);
  RecMutex& operator=(const RecMutex&);
};

/** Utility class for exception-safe locking of recursive mutexes.
 *
 * @deprecated Use Glib::Threads::RecMutex instead.
 */
class RecMutex::Lock
{
public:
  explicit inline Lock(RecMutex& mutex);
  inline Lock(RecMutex& mutex, NotLock);
  inline Lock(RecMutex& mutex, TryLock);

  Lock(const RecMutex::Lock&) = delete;
  RecMutex::Lock& operator=(const RecMutex::Lock&) = delete;

  inline ~Lock();

  inline void acquire();
  inline bool try_acquire();
  inline void release();
  inline bool locked() const;

private:
  RecMutex& mutex_;
  bool      locked_;
};


/** Like Glib::RWLock, but can be defined at compile time.
 * Use @c GLIBMM_STATIC_RW_LOCK_INIT to initialize a StaticRWLock:
 * @code
 * Glib::StaticRWLock rw_lock = GLIBMM_STATIC_RW_LOCK_INIT;
 * @endcode
 * A StaticRWLock can be used without calling Glib::thread_init(), it will
 * silently do nothing then.  That will also work when using the implicit
 * conversion to RWLock&, thus you can safely use RWLock::ReaderLock and
 * RWLock::WriterLock with a StaticRWLock.
 *
 * @deprecated Use Glib::Threads::RWLock instead, which can be used statically.
 */
struct StaticRWLock
{
  void reader_lock();
  bool reader_trylock();
  void reader_unlock();

  void writer_lock();
  bool writer_trylock();
  void writer_unlock();

  operator RWLock&();

  GStaticRWLock* gobj() { return &gobject_; }

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  // Must be public to allow initialization at compile time.
  GStaticRWLock gobject_;
#endif
};

/**
 *
 * @deprecated Use Glib::Threads::RWLock instead.
 */
class RWLock : public StaticRWLock
{
public:
  class ReaderLock;
  class WriterLock;

  RWLock();

  RWLock(const RWLock&) = delete;
  RWLock& operator=(const RWLock&) = delete;

  ~RWLock();
};

/** Utility class for exception-safe locking of read/write locks.
 *
 * @deprecated Use Glib::Threads::RWLock::ReaderLock instead.
 */
class RWLock::ReaderLock
{
public:
  explicit inline ReaderLock(RWLock& rwlock);
  inline ReaderLock(RWLock& rwlock, NotLock);
  inline ReaderLock(RWLock& rwlock, TryLock);

  ReaderLock(const RWLock::ReaderLock&) = delete;
  RWLock::ReaderLock& operator=(const RWLock::ReaderLock&) = delete;

  inline ~ReaderLock();

  inline void acquire();
  inline bool try_acquire();
  inline void release();
  inline bool locked() const;

private:
  RWLock& rwlock_;
  bool    locked_;
};

/** Utility class for exception-safe locking of read/write locks.
 *
 * @deprecated Use Glib::Threads::RWLock::WriterLock instead.
 */
class RWLock::WriterLock
{
public:
  explicit inline WriterLock(RWLock& rwlock);
  inline WriterLock(RWLock& rwlock, NotLock);
  inline WriterLock(RWLock& rwlock, TryLock);

  WriterLock(const RWLock::WriterLock&) = delete;
  RWLock::WriterLock& operator=(const RWLock::WriterLock&) = delete;

  inline ~WriterLock();

  inline void acquire();
  inline bool try_acquire();
  inline void release();
  inline bool locked() const;

private:
  RWLock& rwlock_;
  bool    locked_;
};

/** 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 = nullptr;
 *
 * 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 = nullptr;
 *
 *   return data;
 * }
 * @endcode
 *
 * @deprecated Use Glib::Threads::Cond instead.
 */
class Cond
{
public:
  Cond();

  Cond(const Cond&) = delete;
  Cond& operator=(const Cond&) = delete;

  ~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 timed_wait() methods
   * only inside a loop, which checks for the condition to be true as it is not
   * guaranteed that the waiting thread will find it fulfilled, even if the signaling
   * thread left the condition in that state. This is because another thread can have
   * altered the condition, before the waiting thread got the chance to be woken up,
   * even if the condition itself is protected by a @a Mutex.
   */
  void wait(Mutex& mutex);

  /** Waits until this thread is woken up on this @a Cond, but not longer than until the time, that is specified by @a abs_time.
   * The mutex is unlocked before falling asleep and locked again before resuming.
   *
   * @param mutex a @a Mutex that is currently locked.
   * @param abs_time a max time to wait.
   *
   * @note It is important to use the @a wait() and @a timed_wait() methods
   * only inside a loop, which checks for the condition to be true as it is not
   * guaranteed that the waiting thread will find it fulfilled, even if the signaling
   * thread left the condition in that state. This is because another thread can have
   * altered the condition, before the waiting thread got the chance to be woken up,
   * even if the condition itself is protected by a @a Mutex.
   */
  bool timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time);

  GCond* gobj() { return gobject_; }

private:
  GCond* gobject_;
};


/** Thread-local data pointer.
 *
 * @deprecated Use Glib::Threads::Private instead, which can be used statically.
 */
template <class T>
struct StaticPrivate
{
  using DestroyNotifyFunc =  void (*) (void*);

  static void delete_ptr(void* data);

  inline T* get();
  inline void set(T* data, DestroyNotifyFunc notify_func = &StaticPrivate<T>::delete_ptr);

  GStaticPrivate* gobj() { return &gobject_; }

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  // Must be public to allow initialization at compile time.
  GStaticPrivate gobject_;
#endif
};

/** Thread-local data pointer.
 *
 * @deprecated Use Glib::Threads::Private instead.
 */
template <class T>
class Private
{
public:

  Private(const Private<T>&) = delete;
  Private<T>& operator=(const Private<T>&) = delete;

  using DestructorFunc = void (*) (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_;
};

/** @} group Threads */

/*! A glibmm thread example.
 * @example thread/thread.cc
 */


#ifndef DOXYGEN_SHOULD_SKIP_THIS

/***************************************************************************/
/*  inline implementation                                                  */
/***************************************************************************/

// internal
/** @deprecated This was always for internal glibmm use and is now unecessary even inside glibmm.
 */
void thread_init_impl();

/**** Glib::Mutex::Lock ****************************************************/

inline
Mutex::Lock::Lock(Mutex& mutex)
:
  mutex_  (mutex),
  locked_ (true)
{
  mutex_.lock();
}

inline
Mutex::Lock::Lock(Mutex& mutex, NotLock)
:
  mutex_  (mutex),
  locked_ (false)
{}

inline
Mutex::Lock::Lock(Mutex& mutex, TryLock)
:
  mutex_  (mutex),
  locked_ (mutex.trylock())
{}

inline
Mutex::Lock::~Lock()
{
  if(locked_)
    mutex_.unlock();
}

inline
void Mutex::Lock::acquire()
{
  mutex_.lock();
  locked_ = true;
}

inline
bool Mutex::Lock::try_acquire()
{
  locked_ = mutex_.trylock();
  return locked_;
}

inline
void Mutex::Lock::release()
{
  mutex_.unlock();
  locked_ = false;
}

inline
bool Mutex::Lock::locked() const
{
  return locked_;
}


/**** Glib::RecMutex::Lock *************************************************/

inline
RecMutex::Lock::Lock(RecMutex& mutex)
:
  mutex_  (mutex),
  locked_ (true)
{
  mutex_.lock();
}

inline
RecMutex::Lock::Lock(RecMutex& mutex, NotLock)
:
  mutex_  (mutex),
  locked_ (false)
{}

inline
RecMutex::Lock::Lock(RecMutex& mutex, TryLock)
:
  mutex_  (mutex),
  locked_ (mutex.trylock())
{}

inline
RecMutex::Lock::~Lock()
{
  if(locked_)
    mutex_.unlock();
}

inline
void RecMutex::Lock::acquire()
{
  mutex_.lock();
  locked_ = true;
}

inline
bool RecMutex::Lock::try_acquire()
{
  locked_ = mutex_.trylock();
  return locked_;
}

inline
void RecMutex::Lock::release()
{
  mutex_.unlock();
  locked_ = false;
}

inline
bool RecMutex::Lock::locked() const
{
  return locked_;
}


/**** Glib::RWLock::ReaderLock *********************************************/

inline
RWLock::ReaderLock::ReaderLock(RWLock& rwlock)
:
  rwlock_ (rwlock),
  locked_ (true)
{
  rwlock_.reader_lock();
}

inline
RWLock::ReaderLock::ReaderLock(RWLock& rwlock, NotLock)
:
  rwlock_ (rwlock),
  locked_ (false)
{}

inline
RWLock::ReaderLock::ReaderLock(RWLock& rwlock, TryLock)
:
  rwlock_ (rwlock),
  locked_ (rwlock.reader_trylock())
{}

inline
RWLock::ReaderLock::~ReaderLock()
{
  if(locked_)
    rwlock_.reader_unlock();
}

inline
void RWLock::ReaderLock::acquire()
{
  rwlock_.reader_lock();
  locked_ = true;
}

inline
bool RWLock::ReaderLock::try_acquire()
{
  locked_ = rwlock_.reader_trylock();
  return locked_;
}

inline
void RWLock::ReaderLock::release()
{
  rwlock_.reader_unlock();
  locked_ = false;
}

inline
bool RWLock::ReaderLock::locked() const
{
  return locked_;
}


/**** Glib::RWLock::WriterLock *********************************************/

inline
RWLock::WriterLock::WriterLock(RWLock& rwlock)
:
  rwlock_ (rwlock),
  locked_ (true)
{
  rwlock_.writer_lock();
}

inline
RWLock::WriterLock::WriterLock(RWLock& rwlock, NotLock)
:
  rwlock_ (rwlock),
  locked_ (false)
{}

inline
RWLock::WriterLock::WriterLock(RWLock& rwlock, TryLock)
:
  rwlock_ (rwlock),
  locked_ (rwlock.writer_trylock())
{}

inline
RWLock::WriterLock::~WriterLock()
{
  if(locked_)
    rwlock_.writer_unlock();
}

inline
void RWLock::WriterLock::acquire()
{
  rwlock_.writer_lock();
  locked_ = true;
}

inline
bool RWLock::WriterLock::try_acquire()
{
  locked_ = rwlock_.writer_trylock();
  return locked_;
}

inline
void RWLock::WriterLock::release()
{
  rwlock_.writer_unlock();
  locked_ = false;
}

inline
bool RWLock::WriterLock::locked() const
{
  return locked_;
}


/**** Glib::StaticPrivate **************************************************/

// static
template <class T>
void StaticPrivate<T>::delete_ptr(void* data)
{
  delete static_cast<T*>(data);
}

/** This is only for use by glibmm itself.
 */
void* StaticPrivate_get_helper(GStaticPrivate *private_key);

template <class T> inline
T* StaticPrivate<T>::get()
{
  return static_cast<T*>(StaticPrivate_get_helper(&gobject_));
}

/** This is only for use by glibmm itself.
 */
void StaticPrivate_set_helper(GStaticPrivate *private_key, gpointer data, GDestroyNotify notify);

template <class T> inline
void StaticPrivate<T>::set(T* data, typename StaticPrivate<T>::DestroyNotifyFunc notify_func)
{
  StaticPrivate_set_helper(&gobject_, data, notify_func);
}


/**** Glib::Private ********************************************************/

// static
template <class T>
void Private<T>::delete_ptr(void* data)
{
  delete static_cast<T*>(data);
}

/** This is only for use by glibmm itself.
 */
GPrivate* GPrivate_new_helper(GDestroyNotify notify);

template <class T> inline
Private<T>::Private(typename Private<T>::DestructorFunc destructor_func)
:
  gobject_ (GPrivate_new_helper(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 */

} // namespace Glib


#endif // GLIBMM_DISABLE_DEPRECATED


#endif /* _GLIBMM_THREAD_H */