This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[c++0x] prototype <mutex> implementation
- From: Pedro LamarÃo <pedro dot lamarao at mndfck dot org>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Wed, 19 Mar 2008 00:49:52 -0300
- Subject: [c++0x] prototype <mutex> implementation
Attached is an implementation of <mutex> based on pthreads.
Does it make sense?
From building GCC from source I'm aware that a build without pthread
support is possible.
How should we deal with this in the thread library?
Should we #error out?
--
P.
// Copyright (C) 2008 Pedro Lamarão
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef MUTEX_HPP_
#define MUTEX_HPP_
#include <date_time>
#include <exception>
#include <utility>
#include <pthread.h>
namespace std {
class mutex
{
public:
mutex();
~mutex();
// mutex(const mutex&) = delete;
// mutex& operator=(const mutex&) = delete;
void lock();
bool try_lock();
void unlock();
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m_handle;
}
private:
pthread_mutex_t m_handle;
private:
mutex(const mutex&); // = delete;
mutex& operator=(const mutex&); // = delete;
};
class recursive_mutex;
class timed_mutex;
class recursive_timed_mutex;
struct defer_lock_t { };
struct try_to_lock_t { };
struct adopt_lock_t { };
extern const defer_lock_t defer_lock;
extern const try_to_lock_t try_to_lock;
extern const adopt_lock_t adopt_lock;
class lock_error : public exception
{
public:
virtual const char* what() const throw();
};
template <class Mutex> class lock_guard;
template <class Mutex>
class unique_lock
{
public:
typedef Mutex mutex_type;
// 30.3.3.2.1 construct/copy/destroy
unique_lock() : pm(0), owns(false) { }
explicit unique_lock(mutex_type& m)
: pm(&m), owns(true)
{
m.lock();
}
unique_lock(mutex_type& m, defer_lock_t)
: pm(&m), owns(false) { }
unique_lock(mutex_type& m, try_to_lock_t)
: pm(&m), owns(false)
{
owns = m.try_lock();
}
unique_lock(mutex_type& m, adopt_lock_t)
: pm(&m), owns(true) { }
unique_lock(mutex_type& m, const system_time& abs_time)
: pm(&m), owns(false)
{
owns = m.timed_lock(abs_time);
}
template <class Duration>
unique_lock(mutex_type& m, const Duration& rel_time)
: pm(&m), owns(false)
{
owns = m.timed_lock(rel_time);
}
~unique_lock()
{
if (owns)
pm->unlock();
}
// unique_lock(unique_lock const&) = delete;
// unique_lock& operator=(unique_lock const&) = delete;
#ifdef __GXX_EXPERIMENTAL_CXX0X__
unique_lock(unique_lock&& u)
: pm(u.pm), owns(u.owns)
{
u.pm = NULL;
u.owns = false;
}
unique_lock& operator=(unique_lock&& u)
{
if (owns)
pm->unlock();
pm = u.pm;
owns = u.owns;
u.pm = 0;
u.owns = false;
}
#endif
// 30.3.3.2.2 locking
void lock()
{
if (!pm || owns) {
// FIXME: throw lock_error.
}
pm->lock();
}
bool try_lock()
{
if (!pm || owns) {
// FIXME: throw lock_error.
}
return pm->try_lock();
}
template <class Duration>
bool timed_lock(const Duration& rel_time)
{
if (!pm || owns) {
// FIXME: throw lock_error.
}
return pm->timed_lock(rel_time);
}
bool timed_lock(const system_time& abs_time)
{
if (!pm || owns) {
// FIXME: throw lock_error.
}
return pm->timed_lock(abs_time);
}
void unlock()
{
if (!owns) {
// FIXME: throw lock_error.
}
return pm->unlock();
}
// 30.3.3.2.3 modifiers
#ifdef __GXX_EXPERIMENTAL_CXX0X__
void swap(unique_lock&& u)
{
std::swap(pm, u.pm);
std::swap(owns, u.owns);
}
#else
void swap(unique_lock& u)
{
std::swap(pm, u.pm);
std::swap(owns, u.owns);
}
#endif
mutex_type* release()
{
mutex_type* tmp = pm;
pm = 0;
owns = false;
return tmp;
}
// 30.3.3.2.4 observers
bool owns_lock() const
{
return owns;
}
/*explicit*/ operator bool () const
{
return owns;
}
mutex_type* mutex() const
{
return pm;
}
private:
mutex_type* pm;
bool owns;
private:
unique_lock(unique_lock const&); // = delete;
unique_lock& operator=(unique_lock const&); // = delete;
};
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y)
{
x.swap(y);
}
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template <class Mutex>
void swap(unique_lock<Mutex>&& x, unique_lock<Mutex>& y)
{
x.swap(y);
}
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>&& y)
{
x.swap(y);
}
#endif
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template <class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
#endif
struct once_flag {
/*constexpr*/ once_flag();
// once_flag(const once_flag&) = delete;
// once_flag& operator=(const once_flag&) = delete;
private:
once_flag(const once_flag&); // = delete;
once_flag& operator=(const once_flag&); // = delete;
};
#ifdef __GXX_EXPERIMENTAL_CXX0X__
template<class Callable, class ...Args>
void call_once(once_flag& flag, Callable func, Args&&... args);
#endif
template<class Callable>
void call_once(once_flag& flag, Callable func);
} // std
#endif /*MUTEX_HPP_*/
// Copyright (C) 2008 Pedro Lamarão
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <mutex.hpp>
#include <cassert>
#include <cerrno>
namespace std {
mutex::mutex () {
pthread_mutex_init(&m_handle, 0);
}
mutex::~mutex () {
pthread_mutex_destroy(&m_handle);
}
void mutex::lock () {
pthread_mutex_lock(&m_handle);
}
bool mutex::try_lock () {
int status = pthread_mutex_lock(&m_handle);
return status == 0 ? true : false;
}
void mutex::unlock () {
pthread_mutex_unlock(&m_handle);
}
}