// Generated by gmmproc 2.54.1 -- DO NOT MODIFY!
#ifndef _GLIBMM_THREADS_H
#define _GLIBMM_THREADS_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.
#include <glib.h>
#include <glibmm/error.h>
#include <sigc++/sigc++.h>
#include <string>
#include <cstddef>
namespace Glib
{
/**
* @deprecated The entire Glib::Threads API is deprecated in favor of the
* standard C++ concurrency API in C++11 and C++14.
*/
namespace Threads
{
//The GMMPROC_EXTRA_NAMESPACE() macro is a hint to generate_wrap_init.pl to put it in the Threads sub-namespace
/** @defgroup Threads Threads
* %Thread abstraction; including threads, different mutexes,
* conditions and thread private data.
*
* @deprecated The entire Glib::Threads API is deprecated in favor of the
* standard C++ concurrency API in C++11 and C++14.
* @{
*/
/// @deprecated Please use std::lock_guard or std::unique_lock instead.
enum NotLock { NOT_LOCK };
/// @deprecated Please use std::lock_guard or std::unique_lock instead.
enum TryLock { TRY_LOCK };
class Mutex;
class RecMutex;
class RWLock;
/** %Exception class for thread-related errors.
*
* @deprecated Please use std::lock_guard or std::unique_lock 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.
* 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 Threads::Thread::Exit exception, which will be caught by the internal thread
* entry function.
*
* @note The thread entry slot doesn't have the void* return value that a
* GThreadFunc has. If you want to return any data from your thread,
* you can pass an additional output argument to the thread's entry slot.
*
* @deprecated Please use std::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.
// TODO: At the next ABI break, consider changing const sigc::slot<void>& slot
// to const std::function<void()>& func, if it can be assumed that all supported
// compilers understand the C++11 template class std::function<>.
/** Creates a new thread.
* You can wait for this thread's termination by calling join().
*
* 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 Threads::ThreadError exception is thrown.
*
* Because sigc::trackable is not thread-safe, if the slot represents a
* non-static class method and is created by sigc::mem_fun(), the class concerned
* should not derive from sigc::trackable. You can use, say, boost::bind() or,
* in C++11, std::bind() or a C++11 lambda expression instead of sigc::mem_fun().
*
* @param slot A slot to execute in the new thread.
* @return The new Thread* on success.
* @throw Glib::Threads::ThreadError
*/
static Thread* create(const sigc::slot<void>& slot);
// TODO: At next ABI break, remove the single parameter create
// method and default name to std::string()
/** Creates a new named thread.
* You can wait for this thread's termination by calling join().
*
* 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 Threads::ThreadError exception is thrown.
*
* Because sigc::trackable is not thread-safe, if the slot represents a
* non-static class method and is created by sigc::mem_fun(), the class concerned
* should not derive from sigc::trackable. You can use, say, boost::bind() or,
* in C++11, std::bind() or a C++11 lambda expression instead of sigc::mem_fun().
*
* The @a name can be useful for discriminating threads in a debugger.
* It is not used for other purposes and does not have to be unique.
* Some systems restrict the length of @a name to 16 bytes.
*
* @param slot A slot to execute in the new thread.
* @param name A name for the new thread.
* @return The new Thread* on success.
* @throw Glib::Threads::ThreadError
*
* @newin{2,36}
*/
static Thread* create(const sigc::slot<void>& slot, const std::string& name);
/** 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::Threads::Thread object are released.
*/
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();
const GThread* gobj() const;
private:
// 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::Threads::Thread::Exit();
* @endcode
* Write this if you want to exit from a thread created by Threads::Thread::create().
* Of course you must make sure not to catch Threads::Thread::Exit by accident, i.e.
* when using <tt>catch(...)</tt> somewhere in your code.
*
* @deprecated Please use std::thread instead.
*/
class Thread::Exit
{};
/** A C++ wrapper for the C object.
*
* @param gobject The C instance.
* @return The C++ wrapper.
*
* @relates Glib::Threads::Thread
*
* @deprecated Please use std::thread instead.
*/
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::Threads::Mutex is not recursive, i.e. a thread will deadlock, if it
* already has locked the mutex while calling lock(). Use Glib::Threads::RecMutex
* instead, if you need recursive mutexes.
*
* @deprecated Please use std::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::Threads::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 Please use std::lock_guard or std::unique_lock instead.
*/
class Mutex::Lock
{
public:
explicit inline Lock(Mutex& mutex);
inline Lock(Mutex& mutex, NotLock);
inline Lock(Mutex& mutex, TryLock);
Lock(const Mutex::Lock&) = delete;
Mutex::Lock& operator=(const Mutex::Lock&) = delete;
inline ~Lock();
inline void acquire();
inline bool try_acquire();
inline void release();
inline bool locked() const;
private:
Mutex& mutex_;
bool locked_;
};
/** A C++ wrapper for the C object.
* Do not use operator delete on the returned pointer. If the caller owns the
* GMutex object, the caller must destroy it in the same way as if this function
* had not been called.
*
* @param gobject The C instance.
* @result The GMutex* cast to a Glib::Threads::Mutex*.
*
* @relates Glib::Threads::Mutex
*/
Mutex* wrap(GMutex* gobject);
/** This represents a recursive mutex.
* It is similar to a Mutex with the difference
* that it is possible to lock a RecMutex multiple times in the same
* thread without deadlock. When doing so, care has to be taken to
* unlock the recursive mutex as often as it has been locked.
*
* @deprecated Please use std::recursive_mutex instead.
*/
class RecMutex
{
public:
class Lock;
RecMutex();
RecMutex(const RecMutex&) = delete;
RecMutex& operator=(const RecMutex&) = delete;
~RecMutex();
void lock();
bool trylock();
void unlock();
GRecMutex* gobj() { return &gobject_; }
private:
GRecMutex gobject_;
};
/** Utility class for exception-safe locking of recursive mutexes.
*
* @deprecated Please use std::lock_guard or std::unique_lock 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_;
};
/** A C++ wrapper for the C object.
* Do not use operator delete on the returned pointer. If the caller owns the
* GRecMutex object, the caller must destroy it in the same way as if this function
* had not been called.
*
* @param gobject The C instance.
* @result The GRecMutex* cast to a Glib::Threads::RecMutex*.
*
* @relates Glib::Threads::RecMutex
*/
RecMutex* wrap(GRecMutex* gobject);
/** This represents a reader-writer lock.
* It is similar to a Mutex in that it allows
* multiple threads to coordinate access to a shared resource.
*
* The difference to a mutex is that a reader-writer lock discriminates
* between read-only ('reader') and full ('writer') access. While only
* one thread at a time is allowed write access (by holding the 'writer'
* lock via writer_lock()), multiple threads can gain
* simultaneous read-only access (by holding the 'reader' lock via
* reader_lock()).
*
* @deprecated Please use std::lock_guard or std::unique_lock instead, with std::shared_timed_mutex.
*/
class RWLock
{
public:
class ReaderLock;
class WriterLock;
RWLock();
RWLock(const RWLock&) = delete;
RWLock& operator=(const RWLock&) = delete;
~RWLock();
void reader_lock();
bool reader_trylock();
void reader_unlock();
void writer_lock();
bool writer_trylock();
void writer_unlock();
GRWLock* gobj() { return &gobject_; }
private:
GRWLock gobject_;
};
/** Utility class for exception-safe locking of read/write locks.
*
* @deprecated Please use std::lock_guard or std::unique_lock instead, with std::shared_timed_mutex.
*/
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 Please use std::lock_guard or std::unique_lock instead, with std::shared_timed_mutex.
*/
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.
*
* @deprecated Please use std::condition_variable instead.
*
* @par Usage example:
* @code
* Glib::Threads::Cond data_cond;
* Glib::Threads::Mutex data_mutex;
* void* current_data = nullptr;
*
* void push_data(void* data)
* {
* Glib::Threads::Mutex::Lock lock(data_mutex);
*
* current_data = data;
* data_cond.signal();
* }
*
* void* pop_data()
* {
* Glib::Threads::Mutex::Lock lock(data_mutex);
*
* while (!current_data)
* data_cond.wait(data_mutex);
*
* void* const data = current_data;
* current_data = nullptr;
*
* return data;
* }
* @endcode
*/
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 threads, 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 specified by @a end_time.
* The mutex is unlocked before falling asleep and locked again before resuming.
*
* @par Usage example:
* Extending the example presented in the documentation of class Cond.
* @code
* void* pop_data_timed()
* {
* Glib::Threads::Mutex::Lock lock(data_mutex);
*
* // Wait at most 5 seconds.
* const gint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
* while (!current_data)
* if (!data_cond.wait_until(data_mutex, end_time)
* return nullptr; // timeout
*
* void* const data = current_data;
* current_data = nullptr;
*
* return data;
* }
* @endcode
* The end time is calculated once, before entering the loop, and reused.
* This is the motivation behind the use of absolute time. If a relative time
* of 5 seconds were passed directly to the call and a spurious wakeup
* occurred, the program would have to start over waiting again, which would
* lead to a total wait time of more than 5 seconds.
*
* @param mutex A @a Mutex that is currently locked.
* @param end_time The monotonic time to wait until, in microseconds.
* See g_get_monotonic_time().
* @return <tt>true</tt> if the condition variable was signalled (or in the case
* of a spurious wakeup), <tt>false</tt> if @a end_time has passed.
*
* @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_;
};
/** Thread-local data pointer.
*
* It is recommended that all instances of this class are statically allocated.
* The first time an instance is used (get(), set() or replace() is called)
* glib allocates a scarce OS resource that cannot be deallocated.
*
* @deprecated Please use the thread_local keyword instead.
*/
template <class T>
class Private
{
public:
Private(const Private<T>&) = delete;
Private<T>& operator=(const Private<T>&) = delete;
using DestructorFunc = void (*) (void*);
/** Deletes static_cast<T*>(data)
*/
static void delete_ptr(void* data);
/** Constructor.
*
* @param destructor_func Function pointer, or <tt>nullptr</tt>. If @a destructor_func is not <tt>nullptr</tt>
* and the stored data pointer is not <tt>nullptr</tt>, this function is called when replace()
* is called and when the thread exits.
*/
explicit inline Private(DestructorFunc destructor_func = &Private<T>::delete_ptr);
/** Gets the pointer stored in the calling thread.
*
* @return If no value has yet been set in this thread, <tt>nullptr</tt> is returned.
*/
inline T* get();
/** Sets the pointer in the calling thread without calling <tt>destructor_func()</tt>.
*/
inline void set(T* data);
/** Sets the pointer in the calling thread and calls <tt>destructor_func()</tt>.
* If a function pointer (and not <tt>nullptr</tt>) was specified in the constructor, and
* the stored data pointer before the call to replace() is not <tt>nullptr</tt>, then
* <tt>destructor_func()</tt> is called with this old pointer value.
*
* @newin{2,32}
*/
inline void replace(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 */
/***************************************************************************/
/**** Glib::Threads::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::Threads::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::Threads::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::Threads::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::Threads::Private<T> ********************************************/
// 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)
{
// gobject_ = G_PRIVATE_INIT(destructor_func);
// does not compile with --enable-warnings=fatal.
// GPrivate is a struct, and G_PRIVATE_INIT is an initializer of type { ... }.
// G_PRIVATE_INIT can be used only in initializations.
const GPrivate temp = G_PRIVATE_INIT(destructor_func);
gobject_ = temp;
}
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);
}
template <class T> inline
void Private<T>::replace(T* data)
{
g_private_replace(&gobject_, data);
}
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
} //namespace Threads
} // namespace Glib
#endif // GLIBMM_DISABLE_DEPRECATED
#endif /* _GLIBMM_THREADS_H */