2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-30 20:32:10 +00:00

header-only once for POSIX

[SVN r39695]
This commit is contained in:
Anthony Williams
2007-10-05 09:52:08 +00:00
parent b5ac347a0b
commit b2a095098d
9 changed files with 210 additions and 100 deletions

View File

@@ -25,7 +25,6 @@ lib boost_thread_pthread
pthread/condition.cpp
pthread/exceptions.cpp
pthread/xtime.cpp
pthread/once.cpp
pthread/tss.cpp
: ## requirements ##
<define>BOOST_THREAD_POSIX
@@ -41,7 +40,6 @@ lib boost_thread
pthread/condition.cpp
pthread/exceptions.cpp
pthread/xtime.cpp
pthread/once.cpp
pthread/tss.cpp
: ## requirements ##
<define>BOOST_THREAD_POSIX

View File

@@ -1,16 +1,57 @@
// Copyright 2006 Roland Schwarz.
#ifndef BOOST_THREAD_CONDITION_HPP
#define BOOST_THREAD_CONDITION_HPP
// 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)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040706_HPP
#define BOOST_THREAD_RS06040706_HPP
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(condition.hpp)
#include BOOST_THREAD_PLATFORM(condition_state.hpp)
#endif // BOOST_THREAD_RS06040706_HPP
namespace boost
{
template <class Mutex>
class condition:
private boost::detail::thread::condition_state<Mutex>
{
public:
typedef Mutex mutex_type;
condition();
explicit condition(mutex_type& m);
~condition();
#ifdef BOOST_HAS_DELETED_FUNCTIONS
condition(const condition&) = delete;
condition& operator=(const condition&) = delete;
#endif
void notify_one();
void notify_all();
template <class Lock>
void wait(Lock& lock);
template <class Lock, class Predicate>
void wait(Lock& lock, Predicate pred);
template <class Lock>
bool timed_wait(Lock& lock, const utc_time& abs_time);
template <class Lock, class Predicate>
bool timed_wait(Lock& lock, const utc_time& abs_time, Predicate pred);
#ifndef BOOST_HAS_DELETED_FUNCTIONS
private:
explicit condition(condition&);
condition& operator=(condition&);
#endif
};
}
#include BOOST_THREAD_PLATFORM(condition_impl.hpp)
#include <boost/thread/utc_time.hpp>
#endif

View File

@@ -1,25 +1,74 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// 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)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
#define BOOST_THREAD_PTHREAD_ONCE_HPP
#ifndef BOOST_ONCE_RS06092301_HPP
#define BOOST_ONCE_RS06092301_HPP
// once.hpp
//
// (C) Copyright 2007 Anthony Williams
//
// 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 <boost/thread/pthread/config.hpp>
#include <pthread.h>
#include <boost/assert.hpp>
namespace boost {
typedef pthread_once_t once_flag;
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
struct once_flag
{
pthread_mutex_t mutex;
unsigned flag;
};
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
#define BOOST_ONCE_INIT {PTHREAD_MUTEX_INITIALIZER,0}
} // namespace boost
namespace detail
{
struct pthread_mutex_scoped_lock
{
pthread_mutex_t * mutex;
explicit pthread_mutex_scoped_lock(pthread_mutex_t* mutex_):
mutex(mutex_)
{
int const res=pthread_mutex_lock(mutex);
BOOST_ASSERT(!res);
}
~pthread_mutex_scoped_lock()
{
int const res=pthread_mutex_unlock(mutex);
BOOST_ASSERT(!res);
}
};
}
#endif // BOOST_ONCE_RS06092301_HPP
template<typename Function>
void call_once(once_flag& flag,Function f)
{
long const function_complete_flag_value=0xc15730e2;
#ifdef BOOST_PTHREAD_HAS_ATOMICS
if(::boost::detail::interlocked_read_acquire(&flag.flag)!=function_complete_flag_value)
{
#endif
detail::pthread_mutex_scoped_lock const lock(&flag.mutex);
if(flag.flag!=function_complete_flag_value)
{
f();
#ifdef BOOST_PTHREAD_HAS_ATOMICS
::boost::detail::interlocked_write_release(&flag.flag,function_complete_flag_value);
#else
flag.flag=function_complete_flag_value;
#endif
}
#ifdef BOOST_PTHREAD_HAS_ATOMICS
}
#endif
}
}
#endif

View File

@@ -3,7 +3,7 @@
// interlocked_read_win32.hpp
//
// (C) Copyright 2005-6 Anthony Williams
// (C) Copyright 2005-7 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -15,13 +15,17 @@ namespace boost
{
namespace detail
{
inline long interlocked_read(long* x)
inline long interlocked_read_acquire(long volatile* x)
{
return BOOST_INTERLOCKED_EXCHANGE_ADD(x,0);
long const res=*x;
_ReadWriteBarrier();
return res;
}
inline void* interlocked_read(void** x)
inline void* interlocked_read_acquire(void* volatile* x)
{
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
void* const res=*x;
_ReadWriteBarrier();
return res;
}
}
}

View File

@@ -3,7 +3,7 @@
// once.hpp
//
// (C) Copyright 2005-6 Anthony Williams
// (C) Copyright 2005-7 Anthony Williams
// (C) Copyright 2005 John Maddock
//
// Distributed under the Boost Software License, Version 1.0. (See
@@ -35,29 +35,19 @@ namespace boost
namespace detail
{
struct handle_closer
{
void* const handle_to_close;
handle_closer(void* handle_to_close_):
handle_to_close(handle_to_close_)
{}
~handle_closer()
{
win32::CloseHandle(handle_to_close);
}
};
struct win32_mutex_scoped_lock
{
void* const mutex_handle;
win32_mutex_scoped_lock(void* mutex_handle_):
explicit win32_mutex_scoped_lock(void* mutex_handle_):
mutex_handle(mutex_handle_)
{
win32::WaitForSingleObject(mutex_handle,win32::infinite);
unsigned long const res=win32::WaitForSingleObject(mutex_handle,win32::infinite);
BOOST_ASSERT(!res);
}
~win32_mutex_scoped_lock()
{
win32::ReleaseMutex(mutex_handle);
bool const success=win32::ReleaseMutex(mutex_handle)!=0;
BOOST_ASSERT(success);
}
};
@@ -98,21 +88,21 @@ namespace boost
template<typename Function>
void call_once(Function f,once_flag& flag)
void call_once(once_flag& flag,Function f)
{
// Try for a quick win: if the proceedure has already been called
// just skip through:
long const function_complete_flag_value=0xc15730e2;
if(::boost::detail::interlocked_read(&flag)!=function_complete_flag_value)
if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
{
char mutex_name[::boost::detail::once_mutex_name_length];
void* const mutex_handle(::boost::detail::create_once_mutex(mutex_name,&flag));
BOOST_ASSERT(mutex_handle);
detail::handle_closer const closer(mutex_handle);
detail::win32::handle_manager const closer(mutex_handle);
detail::win32_mutex_scoped_lock const lock(mutex_handle);
if(::boost::detail::interlocked_read(&flag)!=function_complete_flag_value)
if(flag!=function_complete_flag_value)
{
f();
BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);

View File

@@ -10,6 +10,8 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/thread/exceptions.hpp>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
@@ -110,13 +112,84 @@ namespace boost
inline handle create_anonymous_event(event_type type,initial_event_state state)
{
return CreateEventA(0,type,state,0);
handle const res=CreateEventA(0,type,state,0);
return res?res:throw thread_resource_error();
}
inline handle create_anonymous_semaphore(long initial_count,long max_count)
{
return CreateSemaphoreA(NULL,initial_count,max_count,NULL);
handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL);
return res?res:throw thread_resource_error();
}
inline handle duplicate_handle(handle source)
{
handle const current_process=GetCurrentProcess();
long const same_access_flag=2;
handle new_handle=0;
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
return success?new_handle:throw thread_resource_error();
}
inline void release_semaphore(handle semaphore,long count)
{
bool const success=ReleaseSemaphore(semaphore,count,0);
BOOST_ASSERT(success);
}
class handle_manager
{
private:
handle handle_to_manage;
handle_manager(handle_manager&);
handle_manager& operator=(handle_manager&);
void cleanup()
{
if(handle_to_manage)
{
unsigned long result=CloseHandle(handle_to_manage);
BOOST_ASSERT(result);
}
}
public:
explicit handle_manager(handle handle_to_manage_):
handle_to_manage(handle_to_manage_)
{}
handle_manager():
handle_to_manage(0)
{}
handle_manager& operator=(handle new_handle)
{
cleanup();
handle_to_manage=new_handle;
}
operator handle() const
{
return handle_to_manage;
}
handle release()
{
handle const res=handle_to_manage;
handle_to_manage=0;
return res;
}
bool operator!() const
{
return !handle_to_manage;
}
~handle_manager()
{
cleanup();
}
};
}
}
}

View File

@@ -1,45 +0,0 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// 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)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/once.hpp>
namespace {
pthread_key_t key;
pthread_once_t once = PTHREAD_ONCE_INIT;
typedef void (*once_callback)();
}
extern "C" {
static void key_init()
{
pthread_key_create(&key, 0);
}
static void do_once()
{
once_callback* cb = reinterpret_cast<once_callback*>(
pthread_getspecific(key));
(**cb)();
}
}
namespace boost {
void call_once(void (*func)(), once_flag& flag)
{
pthread_once(&once, &key_init);
pthread_setspecific(key, &func);
pthread_once(&flag, do_once);
}
}

View File

@@ -22,7 +22,7 @@ struct condition_test_data
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition condition;
boost::condition<boost::mutex> condition;
int notified;
int awoken;
};

View File

@@ -1,4 +1,4 @@
// (C) Copyright 2006 Anthony Williams
// (C) Copyright 2006-7 Anthony Williams
// 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)
@@ -25,7 +25,7 @@ void call_once_thread()
int my_once_value=0;
for(unsigned i=0;i<loop_count;++i)
{
boost::call_once(initialize_variable, flag);
boost::call_once(flag, initialize_variable);
my_once_value=var_to_init;
if(my_once_value!=1)
{