diff --git a/doc/basic_lock.html b/doc/basic_lock.html
new file mode 100644
index 00000000..dceca444
--- /dev/null
+++ b/doc/basic_lock.html
@@ -0,0 +1,122 @@
+
+
+
+
+
+Boost.Threads, basic_lock
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ basic_lock
+ |
+
+
+
+
+
+This template class defines a generic lock concept type. The
+mutex, try_mutex, timed_mutex,
+recursive_mutex, recursive_try_mutex and
+recursive_timed_mutex all use this template to define their
+lock types.
+
+Like all the Boost.Threads lock models, the
+basic_lock is meant to be short lived and is not thread safe, so should not be shared
+between threads.
+
+Header
+
+
+#include <boost/thread/xlock.hpp>
+ This header is usually not included directly by programmers.
+
+
+Public Interface
+
+
+
+
+ template <typename M>
+ class basic_lock : private boost::noncopyable
+ {
+ public:
+ typedef M mutex_type;
+
+ explicit basic_lock(M& mx, bool lock_it=true);
+ ~basic_lock();
+
+ void lock();
+ void unlock();
+
+ operator const void*() const;
+ };
+
+
+
+
+Constructor
+
+
+ explicit basic_lock(M& mx, bool lock_it=true);
+
+
+Constructs a basic_lock and if lock_it is true then calls lock.
+
+Destructor
+
+
+ ~basic_lock();
+
+
+Destructs the basic_lock and if locked calls unlock.
+
+lock
+
+
+ void lock();
+
+
+Locks the associated mutex model. If the basic_lock
+is already locked then a lock_error is thrown. Depending on the
+locking strategy of the
+mutex model if the calling thread already owns a lock through
+another lock model this may cause a deadlock or for a
+lock_error to be thrown.
+
+unlock
+
+
+ void unlock();
+
+
+Unlocks the associated mutex model. If the basic_lock
+is not already locked then a lock_error is thrown.
+
+const void* Conversion
+
+
+ operator const void*() const;
+
+
+Implicitly converts the lock to a value that can be used in boolean expressions to test if the
+lock is currently locked or not.
+
+Example Usage
+
+See the example given in the documentation for the mutex class.
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/basic_timedlock.html b/doc/basic_timedlock.html
new file mode 100644
index 00000000..8544b17a
--- /dev/null
+++ b/doc/basic_timedlock.html
@@ -0,0 +1,164 @@
+
+
+
+
+
+Boost.Threads, basic_timedlock
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ basic_timedlock
+ |
+
+
+
+
+
+This template class defines a lock type that allows a
+program to attempt to lock the associated mutex model
+blocking only for a specified amount of time. The timed_mutex and
+recursive_timed_mutex use this template to define their
+timed_lock types.
+
+Like all the Boost.Threads lock models, the
+basic_timedlock is meant to be short lived and is not thread safe, so should not
+be shared between threads.
+
+Header
+
+
+#include <boost/thread/xlock.hpp>
+ This header is usually not included directly by programmers. Instead it's
+ included by the mutex model that exposes it.
+
+
+Public Interface
+
+
+
+
+ template <typename M>
+ class basic_timedlock : private boost::noncopyable
+ {
+ public:
+ typedef M mutex_type;
+
+ basic_timedlock(M& mx, const boost::xtime& xt);
+ basic_timedlock(M& mx, bool lock_it);
+ ~basic_timedlock();
+
+ void lock();
+ bool timed_lock(const xtime& xt);
+ void unlock();
+
+ operator const void*() const;
+ };
+
+
+Constructors
+
+
+ basic_timedlock(M& mx, const xtime& xt);
+
+
+Constructs a basic_timedlock and calls timed_lock with xt.
+
+
+ basic_timedlock(M& mx, bool lock_it);
+
+
+Constructs a basic_timedlock and if lock_it is true then
+calls lock.
+
+
Destructor
+
+
+ ~basic_timedlock();
+
+
+Destructs the basic_timedlock and if locked calls unlock.
+
+lock
+
+
+ void lock();
+
+
+Locks the associated mutex model. If the basic_timedlock
+is already locked then a lock_error is thrown. Depending on the
+locking strategy of the
+mutex model if the calling thread already owns a lock through
+another lock model this may cause a deadlock or for a
+lock_error to be thrown.
+
+timed_lock
+
+
+ bool timed_lock(const xtime& xt);
+
+
+Attempts to lock the associated mutex model. If the
+basic_timedlock is already locked then a lock_error is
+thrown. If the mutex model is already locked by another thread
+this operation will wait until xt before returning false.
+
+unlock
+
+
+ void unlock();
+
+
+Unlocks the associated mutex model. If the basic_timedlock
+is not already locked then a lock_error is thrown.
+
+const void* Conversion
+
+
+ operator const void*() const;
+
+
+Implicitly converts the lock to a value that can be used in boolean expressions to test if the
+lock is currently locked or not.
+
+Example Usage
+
+
+#include <boost/thread/mutex.hpp>
+#include <iostream>
+
+int main(int, char*[])
+{
+ boost::mutex mutex;
+ boost::xtime xt;
+ boost::get_xtime(&xt, boost::TIME_UTC);
+ xt.sec += 1;
+ boost::mutex::timed_lock lock(mutex, xt);
+ if (lock)
+ std::cout << "locked" << std::endl;
+ else
+ std::cout << "unlocked" << std::endl;
+ return 0;
+}
+
+
+The output is:
+
+
+locked
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/basic_trylock.html b/doc/basic_trylock.html
new file mode 100644
index 00000000..6c2eabc2
--- /dev/null
+++ b/doc/basic_trylock.html
@@ -0,0 +1,163 @@
+
+
+
+
+
+Boost.Threads, basic_trylock
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ basic_trylock
+ |
+
+
+
+
+
+This template class defines a lock type that allows
+the program to attempt to lock the associated mutex model
+with out blocking. The try_mutex, timed_mutex,
+recursive_try_mutex and
+recursive_timed_mutex use this template to define their
+try_lock types.
+
+Like all the Boost.Threads lock models, the
+basic_trylock is meant to be short lived and is not thread safe, so should not be
+shared between threads.
+
+Header
+
+
+#include <boost/thread/xlock.hpp>
+ This header is usually not included directly by programmers.
+
+
+Public Interface
+
+
+
+
+ template <typename M>
+ class basic_trylock : private boost::noncopyable
+ {
+ public:
+ typedef M mutex_type;
+
+ explicit basic_trylock(M& mx);
+ basic_trylock(M& mx, bool lock_it);
+ ~basic_trylock();
+
+ void lock();
+ bool try_lock();
+ void unlock();
+
+ operator const void*() const;
+ };
+
+
+
+
+Constructors
+
+
+ explicit basic_trylock(M& mx);
+
+
+Constructs a basic_trylock and calls try_lock.
+
+
+ basic_trylock(M& mx, bool lock_it);
+
+
+Constructs a basic_trylock and if lock_it is true then
+calls lock.
+
+
Destructor
+
+
+ ~basic_trylock();
+
+
+Destructs the basic_trylock and if locked calls unlock.
+
+lock
+
+
+ void lock();
+
+
+Locks the associated mutex model. If the basic_trylock
+is already locked then a lock_error is thrown. Depending on the
+locking strategy of the
+mutex model if the calling thread already owns a lock through
+another lock model this may cause a deadlock or for a
+lock_error to be thrown.
+
+try_lock
+
+
+ bool try_lock();
+
+
+Attempts to lock the associated mutex_model. If the basic_trylock
+is already locked then a lock_error is thrown. If the
+mutex model is already locked by another thread this attempt fails
+immediately with out blocking and returns false.
+
+unlock
+
+
+ void unlock();
+
+
+Unlocks the associated mutex model. If the basic_trylock
+is not already locked then a lock_error is thrown.
+
+const void* Conversion
+
+
+ operator const void*() const;
+
+
+Implicitly converts the lock to a value that can be used in boolean expressions to test if the
+lock is currently locked or not.
+
+Example Usage
+
+
+#include <boost/thread/mutex.hpp>
+#include <iostream>
+
+int main(int, char*[])
+{
+ boost::mutex mutex;
+ boost::mutex::try_lock lock(mutex);
+ if (lock)
+ std::cout << "locked" << std::endl;
+ else
+ std::cout << "unlocked" << std::endl;
+ return 0;
+}
+
+
+The output is:
+
+
+locked
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/condition.html b/doc/condition.html
new file mode 100644
index 00000000..20f5bb3e
--- /dev/null
+++ b/doc/condition.html
@@ -0,0 +1,250 @@
+
+
+
+
+
+Boost.Threads, condition
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ condition
+ |
+
+
+
+
+
+A condition is a synchronization primitive that can be employed to suspend a thread
+and reactivate it when a particular condition is met. A condition always works in
+conjunction with a mutex model. The
+mutex model must be locked prior to waiting on the condition,
+which is insured by passing a lock model to the wait
+methods. While the thread is suspended waiting on the condition the
+mutex model is unlocked. When the thread returns from a call
+to one of the wait methods the mutex model is again
+locked.
+
+The condition type is often used to implement the
+Monitor Object pattern.
+
+Header
+
+
+#include <boost/thread/condition.hpp>
+
+
+Public Interface
+
+
+
+
+ class condition : private boost::noncopyable
+ {
+ public:
+ condition();
+ ~condition();
+
+ void notify_one();
+ void notify_all();
+ template <typename L>
+ void wait(L& lock);
+ template <typename L, typename Pr>
+ void wait(L& lock, Pr pred);
+ template <typename L>
+ bool timed_wait(L& lock, const xtime& xt);
+ template <typename L, typename Pr>
+ bool timed_wait(L& lock, const xtime& xt, Pr pred);
+ };
+
+
+
+
+Constructor
+
+
+ condition();
+
+
+Constructs a condition.
+
+Destructor
+
+
+ ~condition();
+
+
+Destructs a condition.
+
+notify_one
+
+
+ void notify_one();
+
+
+If there are any waiting threads releases at least one.
+
+notify_all
+
+
+ void notify_all();
+
+
+Releases all waiting threads.
+
+wait
+
+
+ template <typename L>
+ void wait(L& lock);
+
+
+Releases the lock on the mutex model associated with lock,
+waits for the condition to be notified and then reacquires the lock all in an atomic fashion.
+This version should always be used within a loop checking that the state logically associated
+with the condition has become true. With out the loop race conditions can ensue due to
+possible "spurious wake ups". The second version encapsulates this idiom internally and should
+generally be the preferred method.
+
+
+ template <typename L, typename Pr>
+ void wait(L& lock, Pr pred);
+
+
+Releases the lock on the mutex model associated with lock,
+waits for the condition to be notified and for pred to be true then
+reacquires the lock
+all in an atomic fashion.
+
+timed_wait
+
+
+ template <typename L>
+ bool timed_wait(L& lock, const xtime& xt);
+
+
+Releases the lock on the mutex model associated with the lock,
+waits for the condition to be notified or until xt and then reacquires the lock
+all in an atomic fashion. If the wait timed out the return value is false. This version should
+always be used within a loop checking that the state logically associated with the condition has
+become true. With out the loop race conditions can ensue due to "spurious wake ups". The second version
+encapsulates this idiom internally and should generally be the preferred method.
+
+
+ template <typename L, typename Pr>
+ bool timed_wait(L& lock, const xtime& xt, Pr pred);
+
+
+Releases the lock on the mutex model associated with the lock,
+waits for the condition to be notified and for pred to be true or until xt
+and then reacquires the lock all in an atomic fashion. If the wait timed out the return value is false.
+
+Example Usage
+
+
+#include <iostream>
+#include <vector>
+#include <boost/utility.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+
+class bounded_buffer : private boost::noncopyable
+{
+private:
+ int begin, end, buffered;
+ std::vector<int> circular_buf;
+ boost::condition buffer_not_full, buffer_not_empty;
+ boost::mutex monitor;
+
+ typedef boost::mutex::lock lock;
+
+public:
+ buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
+
+ void send (int m) {
+ lock lk(monitor);
+ while (buffered == circular_buf.size())
+ buffer_not_full.wait(lk);
+ circular_buf[end] = m;
+ end = (end+1) % circular_buf.size();
+ ++buffered;
+ buffer_not_empty.notify_one();
+ }
+ int receive() {
+ lock lk(monitor);
+ while (buffered == 0 && !finished)
+ buffer_not_empty.wait(lk);
+ int i = circular_buf[begin];
+ begin = (begin+1) % circular_buf.size();
+ --buffered;
+ buffer_not_full.notify_one();
+ return i;
+ }
+};
+
+bounded_buffer buf(2);
+
+void sender(void*) {
+ int n = 0;
+ while (n < 100) {
+ buf.send(n);
+ std::cout << "sent: " << n << std::endl;
+ ++n;
+ }
+ buf.send(-1);
+}
+
+void receiver(void*) {
+ int n;
+ do {
+ n = buf.receive();
+ std::cout << "received: " << n << std::endl;
+ } while (n != -1); // -1 indicates end of buffer
+}
+
+int main(int, char*[])
+{
+ boost::thread::create(&sender, 0);
+ boost::thread::create(&receiver, 0);
+ boost::thread::join_all();
+ return 0;
+}
+
+
+Typical output (dependent on scheduling policies) is:
+
+
+sent: 0
+sent: 1
+received: 0
+received: 1
+sent: 2
+sent: 3
+received: 2
+received: 3
+sent: 4
+received: 4
+
+
+
+
+References
+
+Douglas Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann:
+Pattern-Oriented Software Architecture - Volume 2 (Patterns for Concurrent
+and Networked Objects), Wiley, 2000.
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/config.html b/doc/config.html
new file mode 100644
index 00000000..4b943a93
--- /dev/null
+++ b/doc/config.html
@@ -0,0 +1,96 @@
+
+
+
+
+
+Boost.Threads, Configuration Information
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ Configuration Information
+ |
+
+
+
+
+
+Boost.Threads uses several configuration macros in <boost/config.hpp>.
+These macros are documented here. Most of the macros are
+of interest only to developers attempting to provide new implementations of Boost.Threads.
+The one exception to this is BOOST_HAS_THREADS.
+
+
+
+ |
+ Macro
+ |
+
+ Meaning
+ |
+
+
+ |
+ BOOST_HAS_THREADS
+ |
+
+ Indicates that threading support is available. This means both that there is a
+ platform specific implementation for Boost.Threads and that threading
+ support has been enabled in a platform specific manner. For instance, on the
+ Win32 platform there's an implementation for Boost.Threads but unless
+ the program is compiled against one of the multi-threading runtimes (when the
+ compiler will predefine the macro _MT) this macro remains undefined.
+ |
+
+
+ |
+ BOOST_HAS_WINTHREADS
+ |
+
+ Indicates that the platform has Win32 threading libraries that should be used
+ to implement Boost.Threads.
+ |
+
+
+ |
+ BOOST_HAS_PTHREADS
+ |
+
+ Indicates that the platform has POSIX pthreads libraries that should be used
+ to implement Boost.Threads.
+ |
+
+
+ |
+ BOOST_HAS_FTIME
+ |
+
+ Indicates that the implementation should use GetSystemTimeAsFileTime() and
+ the FILETIME type to calculate the current time. This is an implementation
+ detail used by boost::detail::getcurtime().
+ |
+
+
+ |
+ BOOST_HAS_GETTTIMEOFDAY
+ |
+
+ Indicates that the implementation should use gettimeofday() to calculate the
+ current time. This is an implementation detail used by boost::detail::getcurtime().
+ |
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 00000000..29e3c20e
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,64 @@
+
+
+
+
+
+Boost.Threads, Index
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ Index
+ (version 1.00, 8 February 2001)
+ |
+
+
+
+
+
+Contents
+
+
+
+
+
+© Copyright William E. Kempf
+2001
+ Permission to use, copy, modify, distribute and sell this software
+ and its documentation for any purpose is hereby granted without fee,
+ provided that the above copyright notice appear in all copies and
+ that both that copyright notice and this permission notice appear
+ in supporting documentation. William E. Kempf makes no representations
+ about the suitability of this software for any purpose.
+ It is provided "as is" without express or implied warranty.
+
+
+
+
+
diff --git a/doc/introduction.html b/doc/introduction.html
new file mode 100644
index 00000000..eb6402e6
--- /dev/null
+++ b/doc/introduction.html
@@ -0,0 +1,127 @@
+
+
+
+
+
+Boost.Threads, Introduction
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ Introduction
+ |
+
+
+
+
+
+Motivation
+
+With client/server and three-tier architectures becoming common place in today's
+world it's becoming increasingly important for programs to be able to handle parallel
+processing. Modern day operating systems usually provide some support for this
+through native thread APIs. Unfortunately, writing portable code that makes use
+of parallel processing in C++ is made very difficult by a lack of a standard interface
+for these native APIs. Further, these APIs are almost universally C APIs and fail to
+take advantage of C++'s strengths, or to address C++'s issues.
+
+The Boost.Threads library is an attempt to define a portable interface for writing
+parallel processes in C++.
+
+Goals
+
+The Boost.Threads library has several goals that should help to set it apart from
+other solutions. These goals are listed in order of precedence with full descriptions
+below.
+
+
+ - Portability
+
Boost.Threads was designed to be highly portable. The goal is for the
+ interface to be easily implemented on any platform that supports threads,
+ and possibly even on platforms with out native thread support.
+ - Safety
+
Boost.Threads was designed to be as safe as possible. Writing thread
+ safe code is very difficult and successful libraries must strive to insulate
+ the programmer from dangerous constructs as much as possible.
+ - Flexibility
+
Boost.Threads was designed to be flexible. This goal is often at odds
+ with safety. When functionality might be compromised by the desire
+ to keep the interface safe, Boost.Threads has been designed to provide
+ the functionality, but to make it's use prohibitive for general use.
+ - Efficiency
+
Boost.Threads was designed to be as efficient as possible. When building
+ a library on top of another library there is always a danger that the result
+ will be so much slower than the "native" API that programmers are inclined
+ to ignore the higher level API. Boost.Threads was designed to minimize the
+ chances of this occurring. The interfaces have been crafted to allow an
+ implementation the greatest chance of being as efficient as possible. This
+ goal is often at odds with the goal for safety. Every effort was made to
+ insure efficient implementations, but when in conflict safety has always taken
+ precedence.
+
+
+
+Iterative Phases
+
+Another goal of the Boost.Threads was for it to take a dynamic, iterative
+approach in its development. The computing industry is still exploring the concepts of parallel programming.
+Most thread libraries supply only simple primitive concepts for thread synchronization.
+These concepts are very simple, but they are very difficult to use safely or to provide
+formal proofs for constructs built on top of them. Until recently, these primitives
+were "state of the art" and the only concepts available to programmers. Recently
+there has been a lot of research in other concepts, such as in "Communicating Sequential
+Processes." Boost.Threads was designed in iterative steps, providing the building
+blocks necessary for the next step, and giving the researcher the tools necessary to
+explore new concepts in a portable manner.
+
+Given the goal of following a dynamic, iterative approach Boost.Threads shall go through
+several growth cycles. Each phase in its development shall be roughly documented here.
+
+Phase 1, Synchronization Primitives
+
+Boost is all about providing high quality libraries with implementations for many platforms.
+Unfortunately, there's a big problem faced by developers wishing to supply such high quality
+libraries, namely thread safety. The C++ standard doesn't address threads at all, but real
+world programs often make use of native threading support. A portable library that doesn't
+address the issue of thread safety is there for not much help to a programmer who wants to
+use the library in his multi-threaded application. So there's a very great need for portable
+primitives that will allow the library developer to create thread safe implementations. This
+need far out weighs the need for portable methods to create and manage threads.
+
+Because of this need, the first phase of Boost.Threads focuses solely on providing
+portable primitive concepts for thread synchronization. Types provided in this phase include
+the semaphore, mutex/try_mutex/timed_mutex,
+recursive_mutex/recursive_try_mutex/recursive_timed_mutex,
+basic_lock, basic_trylock,
+basic_timedlock and lock_error.
+These are considered the "core" synchronization primitives, though there are others that will
+be added in later phases.
+
+Phase 2, Thread Management and Thread Specific Storage
+
+This phase addresses the creation and management of threads and provides a mechanism for
+thread specific storage (data associated with a thread instance). Thread management is a tricky
+issue in C++, so this phase addresses only the basic needs of multi-threaded program. Later
+phases are likely to add additional functionality in this area. This phase of Boost.Threads
+adds the thread and tss types. With these additions
+the Boost.Threads library can be considered minimal but complete.
+
+The Next Phase
+
+The next phase shall address more advanced synchronization concepts, such as read/write mutexes
+and barriers.
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/lock_concept.html b/doc/lock_concept.html
new file mode 100644
index 00000000..34b8581b
--- /dev/null
+++ b/doc/lock_concept.html
@@ -0,0 +1,60 @@
+
+
+
+
+
+Boost.Threads, Lock Concept
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ Lock Concept
+ |
+
+
+
+
+
+The purpose of a lock concept is to provide an exception safe means for acquiring and
+releasing a mutex model. In other words they are an
+implementation of the Scoped Locking1 pattern.
+
+Lock models are constructed with a reference to a mutex model
+and typically acquire ownership of the mutex model by setting
+its state to locked. They also insure ownership is relinquished in the destructor. Lock
+models also expose methods to query the lock status and to manually lock and unlock the
+mutex model.
+
+Instances of lock models are meant to be short lived, expected to be used at block scope
+only. In particular it should be noted that lock models are not thread safe. Lock models
+must maintain state to indicate whether or not they've been locked and this state is not
+protected by any synchronization concepts. For this reason an instance of a lock model
+should never be shared between multiple threads.
+
+Boost.Threads provides three templates used to expose lock models for specific
+mutex models: basic_lock,
+basic_trylock and
+basic_timedlock.
+
+
+
+Foot Notes
+
+1 Douglas Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann:
+Pattern-Oriented Software Architecture - Volume 2 (Patterns for Concurrent
+and Networked Objects), Wiley, 2000.
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/lock_error.html b/doc/lock_error.html
new file mode 100644
index 00000000..383cf243
--- /dev/null
+++ b/doc/lock_error.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+Boost.Threads, lock_error
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ lock_error
+ |
+
+
+
+
+
+The lock_error class defines an exception type that is thrown by lock operations that
+would deadlock or unlock operations performed by a thread that does not own the lock.
+
+Header
+
+
+#include <boost/thread/thread.hpp>
+
+
+Public Interface
+
+
+ class lock_error : public std::runtime_error
+ {
+ public:
+ lock_error();
+ };
+
+
+Constructor
+
+
+ lock_error();
+
+
+Constructs a lock_error.
+
+Example Usage
+
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+int main(int, char*[])
+{
+ boost::mutex mutex;
+ boost::mutex::lock lock(mutex);
+ try
+ {
+ boost::mutex::lock deadlock(mutex);
+ std::cout << "lock succeeded" << std::endl;
+ }
+ catch (boost::lock_error& err)
+ {
+ std::cout << err.what() << " - deadlock occurred." << std::endl;
+ }
+}
+
+
+The output is:
+
+
+thread lock error - deadlock occurred.
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/mutex.html b/doc/mutex.html
new file mode 100644
index 00000000..fc78a609
--- /dev/null
+++ b/doc/mutex.html
@@ -0,0 +1,210 @@
+
+
+
+
+
+Boost.Threads, mutex
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ mutex / try_mutex / timed_mutex
+ |
+
+
+
+
+
+The mutex, try_mutex and timed_mutex classes define full featured
+mutex models. These type should be used to synchronize access to
+shared resources when recursive locking mechanics need not be employed. Each type adds another
+lock concept, including the basic_lock,
+basic_trylock and basic_timedlock
+types. For the best possible performance you should use the mutex type that supports only the lock
+types that you need.
+
+The mutex, try_mutex and timed_mutex use an Unspecified
+locking strategy, so attempts to recursively lock
+them or attempts to unlock them by threads that don't own a lock on them result in undefined behavior.
+This strategy allows implementations to be as efficient as possible on any given platform. It is, however,
+recommended that implementations include some debugging support to detect misuse when NDEBUG is
+not defined.
+
+Like all the Boost.Threads mutex models, the mutex,
+try_mutex and timed_mutex leave the
+scheduling policy as Unspecified.
+Programmers should assume that threads waiting for a lock on these mutex types shall acquire
+the lock in a random order, though the specific behavior for a given platform may be different.
+
+Header
+
+
+#include <boost/thread/mutex.hpp>
+
+
+Public Interface
+
+
+
+
+ class mutex : private boost::noncopyable
+ {
+ public:
+ typedef boost::basic_lock<mutex> lock;
+
+ mutex();
+ ~mutex();
+ };
+
+
+
+
+Constructor
+
+
+ mutex();
+
+
+Constructs a mutex.
+
+Destructor
+
+
+ ~mutex();
+
+
+Destructs a mutex.
+
+
+
+
+ class try_mutex : private boost::noncopyable
+ {
+ public:
+ typedef boost::basic_lock<try_mutex> lock;
+ typedef boost::basic_trylock<try_mutex> trylock;
+
+ try_mutex();
+ ~try_mutex();
+ };
+
+
+
+
+Constructor
+
+
+ try_mutex();
+
+
+Constructs a try_mutex.
+
+Destructor
+
+
+ ~try_mutex();
+
+
+Destructs a try_mutex.
+
+
+
+
+ class timed_mutex : private boost::noncopyable
+ {
+ public:
+ typedef boost::basic_lock<timed_mutex> lock;
+ typedef boost::basic_trylock<timed_mutex> trylock;
+ typedef boost::basic_timedlock<timed_mutex> timedlock;
+
+ timed_mutex();
+ ~timed_mutex();
+ };
+
+
+
+
+Constructor
+
+
+ timed_mutex();
+
+
+Constructs a timed_mutex.
+
+Destructor
+
+
+ ~timed_mutex();
+
+
+Destructs a mutex.
+
+Example Usage
+
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+boost::mutex io_mutex; // The iostreams are not gauranteed to be thread safe!
+
+class counter
+{
+private:
+ boost::mutex mutex;
+ int count;
+
+public:
+ counter() : count(0) { }
+
+ int increment() {
+ boost::mutex::lock lock(mutex);
+ return ++count;
+ }
+};
+
+counter c;
+
+void change_count(void*)
+{
+ int i = c.increment();
+ boost::mutex::lock lock(io_mutex);
+ std::cout << "count == " << i << std::endl;
+}
+
+int main(int, char*[])
+{
+ const int num_threads = 4;
+ for (int i=0; i < num_threads; ++i)
+ boost::thread::create(&change_count, 0);
+
+ boost::thread::join_all();
+
+ return 0;
+}
+
+
+The output is:
+
+
+count == 1
+count == 2
+count == 3
+count == 4
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/mutex_concept.html b/doc/mutex_concept.html
new file mode 100644
index 00000000..a91ce99d
--- /dev/null
+++ b/doc/mutex_concept.html
@@ -0,0 +1,159 @@
+
+
+
+
+
+Boost.Threads, Mutex Concept
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ Mutex Concept
+ |
+
+
+
+
+
+The purpose of a mutex (short for mutual-exclusion) is to serialize access to
+a resource shared between multiple threads. The mutex concept formalizes this
+idea. A model that implements the mutex concept has two states: locked and
+unlocked. Before using a resource that's shared, a thread would lock the mutex model,
+insuring that it was the only thread accessing the shared resource at a given
+time. When done with the shared resource the thread would unlock the mutex model
+allowing another thread to acquire the lock and use the shared resource.
+
+Traditional C thread APIs, such as pthreads or Windows thread APIs, expose methods to
+lock and unlock a mutex model. This is a dangerous way to expose the needed functionality
+since it's easy to forget to unlock a mutex model that's been locked. When the flow of
+control is complex, with multiple return points, the likelihood that you'll forget to
+unlock a mutex model becomes even greater. With exceptions it becomes nearly impossible
+to insure that you unlock the mutex. Many C++ threading libraries have made use of a
+pattern known as Scoped Locking1 to help insure
+that a programmer did not forget to unlock the mutex model. With this pattern a
+lock concept is employed where the lock model's constructor
+locks the associated mutex model and the destructor unlocks the mutex model. The
+Boost.Threads library takes this pattern to the extreme, where lock concepts are the
+only way to lock and unlock a mutex model: lock and unlock methods are not exposed by any
+mutex models in Boost.Threads. This helps to insure safe usage patterns, especially
+with regard to code that may throw exceptions.
+
+The Boost.Threads library currently defines six mutex models:
+boost::mutex, boost::try_mutex,
+boost::timed_mutex, boost::recursive_mutex,
+boost::recursive_try_mutex and
+boost::recursive_timed_mutex.
+
+
+
+Every mutex model follows one of several locking strategies. These strategies
+define the semantics for the locking operation when the calling thread already
+owns a lock on the mutex model.
+
+Recursive
+
+With a recursive locking strategy when a thread attempts to acquire a lock on
+the mutex model for which it already owns a lock the operation returns successfully.
+Internally a lock count is maintained and the owning thread must unlock the
+mutex model the same number of times that it's locked it before the mutex model's
+state returns to unlocked. Since mutex model's in Boost.Threads expose
+locking functionality only through lock concepts it can be proven that a thread
+will always unlock a mutex model the same number of times that it's locked it.
+This helps to eliminate a whole set of errors typically found in traditional
+C style APIs.
+
+The boost::recursive_mutex,
+boost::recursive_try_mutex
+and boost::recursive_timed_mutex use this locking strategy.
+
+Checked
+
+With a checked locking strategy when a thread attempts to acquire a lock on
+the mutex model for which it already owns a lock the operation will fail with
+some sort of error indication. Further, attempts by a thread to unlock a mutex
+that was not locked by the thread will also return some sort of error indication.
+In Boost.Threads an exception of type boost::lock_error
+is thrown in these cases.
+
+Unchecked
+
+With an unchecked locking strategy when a thread attempts to acquire a lock
+on the mutex model for which it already owns a lock the operation will deadlock. In
+general this locking strategy is less safe than a checked or recursive strategy,
+but it's also a faster strategy and so is employed by many libraries.
+
+Boost.Threads does not provide a mutex model that explicitly uses this
+strategy.
+
+Unspecified
+
+With an unspecified locking strategy when a thread attempts to acquire a lock
+on a mutex model for which it already owns a lock the operation results in
+undefined behavior. When a mutex model has an unspecified locking strategy the
+programmer must assume that the mutex model instead uses an unchecked strategy.
+
+In general a mutex model with an unspecified locking strategy is unsafe, and it
+requires programmer discipline to use the mutex model properly. However, this strategy
+allows an implementation to be as fast as possible with no restrictions on its implementation.
+This is especially true for portable implementations that wrap the native threading support
+of a platform. For this reason the boost::mutex,
+boost::try_mutex and boost::timed_mutex use
+this locking strategy despite the lack of safety.
+
+
+
+Every mutex model follows one of several scheduling policies. These policies
+define the semantics for when a mutex model has more than one thread waiting to
+acquire a lock when the mutex model is unlocked. In other words, the policy defines
+which thread shall acquire the lock in this case.
+
+FIFO
+
+With a FIFO scheduling policy threads waiting for the lock will acquire it in
+a first come first serve order (or First In First Out). This can help prevent a
+high priority thread from starving lower priority threads that are also waiting
+on the mutex lock.
+
+Priority Driven
+
+With a Priority Driven scheduling policy the thread with the highest priority
+acquires the lock. Note that this means that low-priority threads may never acquire
+the lock if the mutex model has high contention and there is always at least one high-priority
+thread waiting. This is known as thread starvation. When multiple threads of the same
+priority are waiting on the mutex lock one of the other scheduling priorities will
+determine which thread shall acquire the lock.
+
+Undefined
+
+Threads acquire the lock in no particular order. Users should assume that
+low-priority threads may wait indefinitely, and that threads of the same
+priority acquire the lock in essentially random order.
+
+Unspecified
+
+The mutex model does not specify which scheduling policy is used. The programmer
+must assume that an undefined scheduling policy is used. In order to insure
+portability, all Boost.Threads mutex models use an unspecified scheduling policy.
+
+
+
+Foot Notes
+
+1 Douglas Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann:
+Pattern-Oriented Software Architecture - Volume 2 (Patterns for Concurrent
+and Networked Objects), Wiley, 2000.
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/recursive_mutex.html b/doc/recursive_mutex.html
new file mode 100644
index 00000000..712a4728
--- /dev/null
+++ b/doc/recursive_mutex.html
@@ -0,0 +1,217 @@
+
+
+
+
+
+Boost.Threads, recursive_mutex
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ recursive_mutex
+ |
+
+
+
+
+
+
+
+The recursive_mutex, recursive_try_mutex and recursive_timed_mutex
+classes define full featured mutex models
+with recursive locking semantics. These models should be used to synchronize access to shared resources
+when recursive locking by a single thread is likely to occur. A good example for this is when a class
+supplies "internal synchronization" to insure thread safety and a method on the class may have to call
+other methods on the class which would also attempt to lock the mutex model.
+
+
Each type adds another lock concept, including the
+basic_lock, basic_trylock and
+basic_timedlock types. For the best possible performance you should use
+the mutex type that supports only the lock types that you need.
+
+The recursive_mutex, recursive_try_mutex and recursive_timed_mutex employ a
+Recursive locking strategy, so attempts to
+recursively lock them succeed and an internal "lock count" is maintained. Attempts to unlock them
+by a thread that does not own a lock on them will result in a lock_error
+exception being thrown.
+
+Like all the Boost.Threads mutex models, the
+recursive_mutex, recursive_try_mutex and recursive_timed_mutex leave the
+scheduling policy as Unspecified. Programmers
+should assume that threads waiting for a lock on them shall acquire the lock in a random order, though the
+specific behavior for a given platform may be different.
+
+Header
+
+
+#include <boost/thread/recursive_mutex.hpp>
+
+
+Public Interface
+
+
+
+
+ class recursive_mutex : private boost::noncopyable
+ {
+ public:
+ typedef boost::basic_lock<recursive_mutex> lock;
+
+ recursive_mutex();
+ ~recursive_mutex();
+ };
+
+
+
+
+Constructor
+
+
+ recursive_mutex();
+
+
+Constructs a recursive_mutex.
+
+Destructor
+
+
+ ~recursive_mutex();
+
+
+Destructs a recursive_mutex.
+
+
+
+
+ class recursive_try_mutex : private boost::noncopyable
+ {
+ public:
+ typedef boost::basic_lock<recursive_try_mutex> lock;
+ typedef boost::basic_trylock<recursive_try_mutex> try_lock;
+
+ recursive_try_mutex();
+ ~recursive_try_mutex();
+ };
+
+
+
+
+Constructor
+
+
+ recursive_try_mutex();
+
+
+Constructs a recursive_try_mutex.
+
+Destructor
+
+
+ ~recursive_try_mutex();
+
+
+Destructs a recursive_try_mutex.
+
+
+
+
+ class recursive_timed_mutex : private boost::noncopyable
+ {
+ public:
+ typedef boost::basic_lock<recursive_timed_mutex> lock;
+ typedef boost::basic_trylock<recursive_timed_mutex> try_lock;
+ typedef boost::basic_timedlock<recursive_timed_mutex> timed_lock;
+
+ recursive_timed_mutex();
+ ~recursive_timed_mutex();
+ };
+
+
+
+
+Constructor
+
+
+ recursive_timed_mutex();
+
+
+Constructs a recursive_timed_mutex.
+
+Destructor
+
+
+ ~recursive_timed_mutex();
+
+
+Destructs a recursive_timed_mutex.
+
+Example Usage
+
+
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+class counter
+{
+private:
+ boost::recursive_mutex mutex;
+ int count;
+
+public:
+ counter() : count(0) { }
+
+ int add(int val) {
+ boost::recursive_mutex::lock lock(mutex);
+ count += val;
+ return count;
+ }
+ int increment() {
+ boost::recursive_mutex::lock lock(mutex);
+ return add(1);
+ }
+};
+
+counter c;
+
+void change_count(void*)
+{
+ std::cout << "count == " << c.increment() << std::endl;
+}
+
+int main(int, char*[])
+{
+ const int num_threads=4;
+
+ for (int i=0; i < num_threads; ++i)
+ boost::thread::create(&change_count, 0);
+
+ boost::thread::join_all();
+
+ return 0;
+}
+
+
+The output is:
+
+
+count == 1
+count == 2
+count == 3
+count == 4
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/removed_atomic_t.html b/doc/removed_atomic_t.html
new file mode 100644
index 00000000..2c22e8e7
--- /dev/null
+++ b/doc/removed_atomic_t.html
@@ -0,0 +1,131 @@
+
+
+
+
+
+Boost.Threads, atomic_t
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ atomic_t
+ |
+
+
+
+
+
+Header
+
+The atomic_t class defines an "atomic integer" type. This class should be used
+to perform thread safe operations on an integral type with out the overhead of locks. Only
+a limited set of integer operations are available with an atomic_t instance.
+
+
+#include <boost/thread/atomic.hpp>
+
+
+Public Interface
+
+
+ class atomic_t
+ {
+ public:
+ typedef implementation defined value_type;
+
+ explicit atomic_t(value_type val=0);
+ };
+
+ atomic_t::value_type read(const atomic_t& x);
+ atomic_t::value_type increment(atomic_t& x);
+ atomic_t::value_type decrement(atomic_t& x);
+ atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y);
+ atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z);
+
+
+Constructor
+
+
+ atomic_t(atomic_t::value_type val=0);
+
+
+Constructs an atomic_t and sets its value to val.
+
+read
+
+
+ atomic_t::value_type read(const atomic_t& x);
+
+
+Gets the current value of x.
+
+increment
+
+
+ atomic_t::value_type increment(atomic_t& x);
+
+
+Increments x and returns a value < 0 if the result is less than 0,
+> 0 if the result is greater than 0 and == 0 if the result is equal to
+0.
+
+decrement
+
+
+ atomic_t::value_type decrement(atomic_t& x);
+
+
+Decrements x and returns a value < 0 if the result is less than 0,
+> 0 if the result is greater than 0 and == 0 if the result is equal to
+0.
+
+swap
+
+
+ atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y);
+
+
+Assigns the value of y to x and returns the value of x prior
+to the swap.
+
+compare_swap
+
+
+ atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z);
+
+
+Compares the value of z to the value of x and if equal sets the value of
+x to the value of y and returns the value of x prior to the swap.
+
+Example Usage
+
+
+#include <boost/thread/atomic.hpp>
+#include <boost/test/test_tools.hpp>
+
+int test_main(int, char*[])
+{
+ boost::atomic_t a;
+ BOOST_TEST_VERIFY(boost::read(a) == 0);
+ BOOST_TEST_VERIFY(boost::increment(a) > 0);
+ BOOST_TEST_VERIFY(boost::decrement(a) == 0);
+ BOOST_TEST_VERIFY(boost::swap(a, 1) == 0);
+ BOOST_TEST_VERIFY(boost::swap(a, 2, 0) == 1);
+ BOOST_TEST_VERIFY(boost::read(a) == 1);
+}
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/semaphore.html b/doc/semaphore.html
new file mode 100644
index 00000000..c2ce466b
--- /dev/null
+++ b/doc/semaphore.html
@@ -0,0 +1,152 @@
+
+
+
+
+
+Boost.Threads, semaphore
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ semaphore
+ |
+
+
+
+
+
+The semaphore class defines a classic synchronization primitive invented by the
+Dutch computer scientist Edsger W. Dijkstra. A semaphore manages an internal counter. This
+counter may never go below zero, or above a specified maximum value. When calling
+semaphore::down the calling thread will block until the value is non-zero and then
+decrements the value in a single atomic operation. When calling semaphore::up the
+calling thread will increment the value in a single atomic operation, failing if the value has
+already reached the specified maximum.
+
+The semaphore is the simplest synchronization primitive available and is generally the
+primitive used to build other synchronization concepts at some level of implementation. For this
+reason Boost.Threads defines the semaphore type in the classic form. This simplifies
+usage and implementation, but it means that the interface is not as safe as other Boost.Threads
+interfaces. Unlike the mutex models supplied by Boost.Threads
+there is no lock_concept for the semaphore to help insure proper
+usage. Care should be taken when using a semaphore object to insure deadlock and
+race conditions do not occur.
+
+Header
+
+
+#include <boost/thread/semaphore.hpp>
+
+
+Public Interface
+
+
+ class semaphore : private boost::noncopyable
+ {
+ public:
+ explicit semaphore(unsigned count=0, unsigned max=0);
+ ~semaphore();
+
+ bool up(unsigned count=1, unsigned* prev=0);
+ void down();
+ bool down(const xtime& xt);
+ };
+
+
+Constructor
+
+
+ explicit semaphore(unsigned count=0, unsigned max=0);
+
+
+Constructs a semaphore. The count parameter is used to set the initial
+semaphore count and the max parameter is used to set the maximum value for the
+semaphore. If max is 0 then the maximum value is set to the maximum
+possible value for the implementation.
+
+Destructor
+
+
+ ~semaphore();
+
+
+Destructs a semaphore.
+
+up
+
+
+ bool up(unsigned count=1, unsigned* prev=0);
+
+
+Increments the semaphore by count and optionally returns the previous value of the semaphore
+in prev. If the semaphore's value is already at the maximum value specified in the
+constructor then this operation fails immediately and returns a false value.
+
+down
+
+
+ void down();
+
+
+Decrements the semaphore by one, blocking indefinately if the semaphore's value is currently zero.
+
+
+ bool down(const xtime& xt);
+
+
+Decrements the semaphore by one, blocking until xt if the semaphore's value is currently zero.
+If the operation times out a false value is returned.
+
+Example Usage
+
+
+#include <boost/thread/semaphore.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+int global_data = 0;
+boost::semaphore global_semaphore;
+
+void change_global_data(void*)
+{
+ global_semaphore.down();
+ ++global_data;
+ std::cout << "global_data == " << global_data << std::endl;
+ global_semaphore.up();
+}
+
+int main(int, char*[])
+{
+ const int num_threads = 4;
+ for (int i=0; i < num_threads; ++i)
+ boost::thread::create(&change_global_data, 0);
+
+ boost::thread::join_all();
+
+ return 0;
+}
+
+
+The output is:
+
+
+global_data == 1
+global_data == 2
+global_data == 3
+global_data == 4
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/thread.html b/doc/thread.html
new file mode 100644
index 00000000..76a5c163
--- /dev/null
+++ b/doc/thread.html
@@ -0,0 +1,212 @@
+
+
+
+
+
+Boost.Threads, thread
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ thread
+ |
+
+
+
+
+
+The thread class provides the functionality need to create and manage threads
+within the Boost.Threads library.
+
+Header
+
+
+#include <boost/thread/thread.hpp>
+
+
+Public Interface
+
+
+
+
+ class thread
+ {
+ public:
+ thread();
+ thread(const thread& other);
+ ~thread();
+
+ thread& operator=(const thread& other);
+ thread& swap(thread& other);
+ bool operator==(const thread& other);
+ bool operator!=(const thread& other);
+ bool is_alive() const;
+ void join();
+
+ static thread create(void (*threadfunc)(void*), void* param);
+ static thread self();
+ static void join_all();
+ static void sleep(const xtime& xt);
+ static void yield();
+ };
+
+
+
+
+Constructor
+
+
+ thread();
+
+
+Constructs a thread object that's not associated with any running thread.
+
+
+ thread(const thread& other);
+
+
+Copy constructs a thread object, adding a reference to the associated running thread.
+
+Destructor
+
+
+ ~thread();
+
+
+Destructs a thread, removing a reference to the associated running thread.
+
+Assignment
+
+
+ thread& operator=(const thread& other);
+
+
+Assigns the thread to reference the same running thread associated with other.
+
+swap
+
+
+ thread& swap(thread& other);
+
+
+Swaps the thread with other, exchanging the references to the respective
+associated running threads.
+
+Comparison Operators
+
+
+ bool operator==(const thread& other);
+ bool operator!=(const thread& other);
+
+
+Compares the thread to other to see if they refer to the same associated
+running threads.
+
+is_alive
+
+
+ bool is_alive() const;
+
+
+Determines if the associated running thread is still executing. This operation is only really
+useful to perform "busy waits" on the thread since any other use is likely to result in a race
+condition.
+
+join
+
+
+ void join();
+
+
+Causes the current thread to "join" the associated running thread. In other words, the current
+thread will block until the associated running thread finishes its execution.
+
+create
+
+
+ static thread create(void (*threadfunc)(void*), void* param);
+
+
+Creates a running thread which calls threadfunc passing it a value of param.
+
+self
+
+
+ static thread self();
+
+
+Returns a thread referencing the currently running thread.
+
+join_all
+
+
+ static void join_all();
+
+
+Causes the current thread to "join" all the other currently running threads. In other words, the
+current thread will block until all the other running threads finish their execution.
+
+sleep
+
+
+ static void sleep(const xtime& xt);
+
+
+Causes the current thread to block until xt.
+
+yield
+
+
+ static void yield();
+
+
+Causes the current thread to give up the rest of its time to any other thread that may be waiting
+on CPU time.
+
+Example Usage
+
+
+#include <boost/thread/thread.hpp>
+#include <iostram>
+
+void alarm(void* p)
+{
+ int* pn = static_cast(p);
+
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += *pn;
+
+ boost::thread::sleep(xt);
+
+ std::cout << "alarm sounded..." << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+ int secs = 5;
+ std::cout << "setting alarm for 5 seconds..." << std::endl;
+ boost::thread::create(&alarm, &secs);
+ boost::thread::join_all();
+}
+
+
+The output is:
+
+
+setting alarm for 5 seconds...
+alarm sounded...
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/doc/tss.html b/doc/tss.html
new file mode 100644
index 00000000..650ad230
--- /dev/null
+++ b/doc/tss.html
@@ -0,0 +1,125 @@
+
+
+
+
+
+Boost.Threads, tss
+
+
+
+
+
+
+
+ 
+ |
+
+ Boost.Threads
+ tss
+ |
+
+
+
+
+
+The tss class defines an interface for using thread specific storage. Thread
+specific storage is data associated with individual threads and is often used to make
+operations that rely on global data thread safe.
+
+Header
+
+
+#include <boost/thread/tss.hpp>
+
+
+Public Interface
+
+
+
+
+ class tss
+ {
+ public:
+ tss();
+ ~tss();
+
+ void* get() const;
+ bool set(void* value);
+ };
+
+
+
+
+Constructor
+
+
+ tss();
+
+
+Constructs a tss object for accessing thread specific storage.
+
+Destructor
+
+
+ ~tss();
+
+
+Destructs a tss.
+
+get
+
+
+ void* get() const;
+
+
+Retrieves the thread specific storage for the current thread.
+
+set
+
+
+ bool set(void* value);
+
+
+Sets the thread specific storage for the current thread. Returns false on failure.
+
+Example Usage
+
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/tss.hpp>
+#include <cassert>
+
+boost::tss value;
+
+void increment()
+{
+ int* p = static_cast(value.get());
+ ++*p;
+}
+
+void thread_proc(void*)
+{
+ value.set(new int(0)); // initialize the thread's storage
+ for (int i=0; i<10; ++i)
+ {
+ increment();
+ int* p = static_cast(value.get());
+ assert(*p == i+1);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ for (int i=0; i<5; ++i)
+ boost::thread::create(&thread_proc, 0);
+ boost::thread::join_all();
+}
+
+
+
+
+Copyright William E. Kempf
+2001 all rights reserved.
+
+
+
diff --git a/example/Jamfile b/example/Jamfile
index e69de29b..acab3d97 100644
--- a/example/Jamfile
+++ b/example/Jamfile
@@ -0,0 +1,5 @@
+SubDir TOP example ;
+
+SubInclude TOP example monitor ;
+SubInclude TOP example starvephil ;
+SubInclude TOP example tennis ;
\ No newline at end of file
diff --git a/example/monitor/Jamfile b/example/monitor/Jamfile
new file mode 100644
index 00000000..19827844
--- /dev/null
+++ b/example/monitor/Jamfile
@@ -0,0 +1,11 @@
+SubDir TOP example monitor ;
+
+exe monitor
+ : monitor.cpp
+ ../../src/threads
+ ## Requirements ##
+ : ../..
+ multi
+ ## default-BUILD ##
+ : debug release
+ ;
diff --git a/example/monitor/monitor.cpp b/example/monitor/monitor.cpp
new file mode 100644
index 00000000..54450b60
--- /dev/null
+++ b/example/monitor/monitor.cpp
@@ -0,0 +1,101 @@
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+ const int ITERS = 100;
+ boost::mutex io_mutex;
+};
+
+template
+class buffer_t : public M, public boost::condition
+{
+public:
+ typedef typename M::lock lock;
+
+ buffer_t(int n)
+ : p(0), c(0), full(0), buf(n)
+ {
+ }
+
+ void send(int m)
+ {
+ lock lk(*this);
+ while (full == buf.size())
+ wait(lk);
+ buf[p] = m;
+ p = (p+1) % buf.size();
+ ++full;
+ notify_all();
+ }
+ int receive()
+ {
+ lock lk(*this);
+ while (full == 0)
+ wait(lk);
+ int i = buf[c];
+ c = (c+1) % buf.size();
+ --full;
+ notify_all();
+ return i;
+ }
+
+ static buffer_t& get_buffer()
+ {
+ static buffer_t buf(2);
+ return buf;
+ }
+
+ static void do_sender_thread(void*)
+ {
+ for (int n = 0; n < ITERS; ++n)
+ {
+ get_buffer().send(n);
+ {
+ volatile boost::mutex::lock lock(io_mutex);
+ std::cout << "sent: " << n << std::endl;
+ }
+ }
+ }
+
+ static void do_receiver_thread(void*)
+ {
+ int n;
+ do
+ {
+ n = get_buffer().receive();
+ {
+ volatile boost::mutex::lock lock(io_mutex);
+ std::cout << "received: " << n << std::endl;
+ }
+ } while (n < ITERS - 1);
+ }
+
+private:
+ unsigned int p, c, full;
+ std::vector buf;
+};
+
+template
+void do_test(M* dummy=0)
+{
+ typedef buffer_t buffer_type;
+ buffer_type::get_buffer();
+ boost::thread::create(&buffer_type::do_sender_thread, 0);
+ boost::thread::create(&buffer_type::do_receiver_thread, 0);
+ boost::thread::join_all();
+}
+
+void test_buffer()
+{
+ do_test();
+ do_test();
+}
+
+int main()
+{
+ test_buffer();
+ return 0;
+}
diff --git a/example/starvephil/Jamfile b/example/starvephil/Jamfile
new file mode 100644
index 00000000..236cbc1f
--- /dev/null
+++ b/example/starvephil/Jamfile
@@ -0,0 +1,11 @@
+SubDir TOP example starvephil ;
+
+exe starvephil
+ : starvephil.cpp
+ ../../src/threads
+ ## Requirements ##
+ : ../..
+ multi
+ ## default-BUILD ##
+ : debug release
+ ;
diff --git a/example/starvephil/starvephil.cpp b/example/starvephil/starvephil.cpp
new file mode 100644
index 00000000..ffb5b45c
--- /dev/null
+++ b/example/starvephil/starvephil.cpp
@@ -0,0 +1,153 @@
+#include
+#include
+#include
+#include
+#include
+
+namespace
+{
+ boost::mutex iomx;
+};
+
+class canteen
+{
+public:
+ canteen() : m_chickens(0) { }
+
+ void get(int id)
+ {
+ boost::mutex::lock lock(m_mutex);
+ while (m_chickens == 0)
+ {
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << id <<
+ ": wot, no chickens? I'll WAIT ..." << std::endl;
+ }
+ m_condition.wait(lock);
+ }
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << id <<
+ ": those chickens look good ... one please ..." << std::endl;
+ }
+ m_chickens--;
+ }
+ void put(int value)
+ {
+ boost::mutex::lock lock(m_mutex);
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() <<
+ ") Chef: ouch ... make room ... this dish is very hot ..." << std::endl;
+ }
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 3;
+ boost::thread::sleep(xt);
+ m_chickens += value;
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() <<
+ ") Chef: more chickens ... " << m_chickens <<
+ " now available ... NOTIFYING ..." << std::endl;
+ }
+ m_condition.notify_all();
+ }
+
+private:
+ boost::mutex m_mutex;
+ boost::condition m_condition;
+ int m_chickens;
+};
+
+canteen g_canteen;
+
+void chef(void*)
+{
+ const int chickens = 4;
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
+ }
+ for (;;)
+ {
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
+ }
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 2;
+ boost::thread::sleep(xt);
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Chef: " << chickens
+ << " chickens, ready-to-go ..." << std::endl;
+ }
+ g_canteen.put(chickens);
+ }
+}
+
+struct phil
+{
+ phil(int id) : m_id(id) { }
+ void run() {
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl;
+ }
+ for (;;)
+ {
+ if (m_id > 0)
+ {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 3;
+ boost::thread::sleep(xt);
+ }
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << m_id
+ << ": gotta eat ..." << std::endl;
+ }
+ g_canteen.get(m_id);
+ {
+ boost::mutex::lock lock(iomx);
+ std::cout << "(" << clock() << ") Phil" << m_id
+ << ": mmm ... that's good ..." << std::endl;
+ }
+ }
+ }
+ static void do_thread(void* param) {
+ static_cast(param)->run();
+ }
+
+ int m_id;
+};
+
+struct thread_adapt
+{
+ thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
+ int operator()() const
+ {
+ _func(_param);
+ return 0;
+ }
+
+ void (*_func)(void*);
+ void* _param;
+};
+
+int main(int argc, char* argv[])
+{
+ boost::thread::create(&chef, 0);
+ phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
+ boost::thread::create(&phil::do_thread, &p[0]);
+ boost::thread::create(&phil::do_thread, &p[1]);
+ boost::thread::create(&phil::do_thread, &p[2]);
+ boost::thread::create(&phil::do_thread, &p[3]);
+ boost::thread::create(&phil::do_thread, &p[4]);
+ boost::thread::join_all();
+ return 0;
+}
diff --git a/example/tennis/Jamfile b/example/tennis/Jamfile
new file mode 100644
index 00000000..ca563d36
--- /dev/null
+++ b/example/tennis/Jamfile
@@ -0,0 +1,11 @@
+SubDir TOP example tennis ;
+
+exe tennis
+ : tennis.cpp
+ ../../src/threads
+ ## Requirements ##
+ : ../..
+ multi
+ ## default-BUILD ##
+ : debug release
+ ;
diff --git a/example/tennis/tennis.cpp b/example/tennis/tennis.cpp
new file mode 100644
index 00000000..b1cbf279
--- /dev/null
+++ b/example/tennis/tennis.cpp
@@ -0,0 +1,105 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum game_state
+{
+ START,
+ PLAYER_A,
+ PLAYER_B,
+ GAME_OVER,
+ ONE_PLAYER_GONE,
+ BOTH_PLAYERS_GONE
+};
+
+int state;
+boost::mutex mutex;
+boost::condition cond;
+
+char* player_name(int state)
+{
+ if (state == PLAYER_A)
+ return "PLAYER-A";
+ if (state == PLAYER_B)
+ return "PLAYER-B";
+ throw "bad player";
+ return 0;
+}
+
+void player(void* param)
+{
+ boost::mutex::lock lock(mutex);
+
+ int active = (int)param;
+ int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
+
+ while (state < GAME_OVER)
+ {
+ std::cout << player_name(active) << ": Play." << std::endl;
+ state = other;
+ cond.notify_all();
+ do
+ {
+ cond.wait(lock);
+ if (state == other)
+ std::cout << "---" << player_name(active) << ": Spurious wakeup!" << std::endl;
+ } while (state == other);
+ }
+
+ ++state;
+ std::cout << player_name(active) << ": Gone." << std::endl;
+ cond.notify_all();
+}
+
+struct thread_adapt
+{
+ thread_adapt(void (*func)(void*), void* param) : _func(func), _param(param) { }
+ int operator()() const
+ {
+ _func(_param);
+ return 0;
+ }
+
+ void (*_func)(void*);
+ void* _param;
+};
+
+int main(int argc, char* argv[])
+{
+ state = START;
+
+ boost::thread::create(&player, (void*)PLAYER_A);
+ boost::thread::create(&player, (void*)PLAYER_B);
+
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt);
+ {
+ boost::mutex::lock lock(mutex);
+ std::cout << "---Noise ON..." << std::endl;
+ }
+
+ for (int i = 0; i < 1000000; ++i)
+ cond.notify_all();
+
+ {
+ boost::mutex::lock lock(mutex);
+ std::cout << "---Noise OFF..." << std::endl;
+ state = GAME_OVER;
+ cond.notify_all();
+ do
+ {
+ cond.wait(lock);
+ } while (state != BOTH_PLAYERS_GONE);
+ }
+
+ std::cout << "GAME OVER" << std::endl;
+
+ boost::thread::join_all();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/src/Jamfile b/src/Jamfile
new file mode 100644
index 00000000..532dd546
--- /dev/null
+++ b/src/Jamfile
@@ -0,0 +1,17 @@
+SubDir TOP src ;
+
+lib threads
+ : condition.cpp
+ mutex.cpp
+ recursive_mutex.cpp
+ semaphore.cpp
+ thread.cpp
+ tss.cpp
+ xtime.cpp
+ ## Requirements ##
+ : ..
+ multi
+ ## default-BUILD ##
+ : debug release
+ ;
+
diff --git a/src/_atomic.cpp b/src/_atomic.cpp
new file mode 100644
index 00000000..8a56faf1
--- /dev/null
+++ b/src/_atomic.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ */
+
+#include
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+#endif
+
+namespace boost {
+ atomic_t::value_type read(const atomic_t& x)
+ {
+ return x._value;
+ }
+
+#if defined(BOOST_HAS_WINTHREADS)
+ atomic_t::value_type increment(atomic_t& x)
+ {
+ return InterlockedIncrement(const_cast(&x._value));
+ }
+
+ atomic_t::value_type decrement(atomic_t& x)
+ {
+ return InterlockedDecrement(const_cast(&x._value));
+ }
+
+ atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y)
+ {
+ return InterlockedExchange(const_cast(&x._value), y);
+ }
+
+ atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z)
+ {
+ return InterlockedCompareExchange(const_cast(&x._value), y, z);
+ }
+#else
+ atomic_t::value_type increment(atomic_t& x)
+ {
+ mutex::lock lock(x._mutex);
+ return ++x._value;
+ }
+
+ atomic_t::value_type decrement(atomic_t& x)
+ {
+ mutex::lock lock(x._mutex);
+ return --x._value;
+ }
+
+ atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y)
+ {
+ mutex::lock lock(x._mutex);
+ atomic_t::value_type temp = x._value;
+ x._value = y;
+ return temp;
+ }
+
+ atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z)
+ {
+ mutex::lock lock(x._mutex);
+ atomic_t::value_type temp = x._value;
+ if (temp == z)
+ x._value = y;
+ return temp;
+ }
+#endif
+} // namespace boost
diff --git a/src/atomic.cpp b/src/atomic.cpp
new file mode 100644
index 00000000..453e1e89
--- /dev/null
+++ b/src/atomic.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ */
+
+#include
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+#endif
+
+namespace boost {
+ atomic_t::value_type read(const atomic_t& x)
+ {
+ return x.value;
+ }
+
+#if defined(BOOST_HAS_WINTHREADS)
+ atomic_t::value_type increment(atomic_t& x)
+ {
+ return InterlockedIncrement(const_cast(&x.value));
+ }
+
+ atomic_t::value_type decrement(atomic_t& x)
+ {
+ return InterlockedDecrement(const_cast(&x.value));
+ }
+
+ atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y)
+ {
+ return InterlockedExchange(const_cast(&x.value), y);
+ }
+
+ atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z)
+ {
+ return InterlockedCompareExchange(const_cast(&x.value), y, z);
+ }
+#else
+ atomic_t::value_type increment(atomic_t& x)
+ {
+ mutex::lock lock(x._mutex);
+ return ++x.value;
+ }
+
+ atomic_t::value_type decrement(atomic_t& x)
+ {
+ mutex::lock lock(x._mutex);
+ return --x.value;
+ }
+
+ atomic_t::value_type swap(atomic_t& x, atomic_t::value_type y)
+ {
+ mutex::lock lock(x._mutex);
+ atomic_t::value_type temp = x.value;
+ x.value = y;
+ return temp;
+ }
+
+ atomic_t::value_type compare_swap(atomic_t& x, atomic_t::value_type y, atomic_t::value_type z)
+ {
+ mutex::lock lock(x._mutex);
+ atomic_t::value_type temp = x.value;
+ if (temp == z)
+ x.value = y;
+ return temp;
+ }
+#endif
+} // namespace boost
diff --git a/src/condition.cpp b/src/condition.cpp
new file mode 100644
index 00000000..2b684ca5
--- /dev/null
+++ b/src/condition.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ * 22 May 01 Modified to use xtime for time outs.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include "timeconv.inl"
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+#elif defined(BOOST_HAS_PTHREADS)
+# include
+#endif
+
+namespace boost
+{
+#if defined(BOOST_HAS_WINTHREADS)
+ condition::condition()
+ : _gone(0), _blocked(0), _waiting(0)
+ {
+ _gate = reinterpret_cast(CreateSemaphore(0, 1, 1, 0));
+ _queue = reinterpret_cast(CreateSemaphore(0, 0, std::numeric_limits::max(), 0));
+ _mutex = reinterpret_cast(CreateMutex(0, 0, 0));
+
+ if (!_gate || !_queue || !_mutex)
+ {
+ int res = CloseHandle(reinterpret_cast(_gate));
+ assert(res);
+ res = CloseHandle(reinterpret_cast(_queue));
+ assert(res);
+ res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+
+ throw std::runtime_error("boost::condition : failure to construct");
+ }
+ }
+
+ condition::~condition()
+ {
+ int res = CloseHandle(reinterpret_cast(_gate));
+ assert(res);
+ res = CloseHandle(reinterpret_cast(_queue));
+ assert(res);
+ res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void condition::notify_one()
+ {
+ unsigned signals = 0;
+
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ if (_waiting != 0) // the _gate is already closed
+ {
+ if (_blocked == 0)
+ {
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ return;
+ }
+
+ ++_waiting;
+ --_blocked = 0;
+ }
+ else
+ {
+ res = WaitForSingleObject(reinterpret_cast(_gate), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ if (_blocked > _gone)
+ {
+ if (_gone != 0)
+ {
+ _blocked -= _gone;
+ _gone = 0;
+ }
+ signals = _waiting = 1;
+ --_blocked;
+ }
+ else
+ {
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0);
+ assert(res);
+ }
+
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+
+ if (signals)
+ {
+ res = ReleaseSemaphore(reinterpret_cast(_queue), signals, 0);
+ assert(res);
+ }
+ }
+ }
+
+ void condition::notify_all()
+ {
+ unsigned signals = 0;
+
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ if (_waiting != 0) // the _gate is already closed
+ {
+ if (_blocked == 0)
+ {
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ return;
+ }
+
+ _waiting += (signals = _blocked);
+ _blocked = 0;
+ }
+ else
+ {
+ res = WaitForSingleObject(reinterpret_cast(_gate), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ if (_blocked > _gone)
+ {
+ if (_gone != 0)
+ {
+ _blocked -= _gone;
+ _gone = 0;
+ }
+ signals = _waiting = _blocked;
+ _blocked = 0;
+ }
+ else
+ {
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0);
+ assert(res);
+ }
+
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+
+ if (signals)
+ {
+ res = ReleaseSemaphore(reinterpret_cast(_queue), signals, 0);
+ assert(res);
+ }
+ }
+ }
+
+ void condition::enter_wait()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_gate), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ ++_blocked;
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0);
+ assert(res);
+ }
+
+ void condition::do_wait()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_queue), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ unsigned was_waiting=0;
+ unsigned was_gone=0;
+
+ res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ was_waiting = _waiting;
+ was_gone = _gone;
+ if (was_waiting != 0)
+ {
+ if (--_waiting == 0)
+ {
+ if (_blocked != 0)
+ {
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0); // open _gate
+ assert(res);
+ was_waiting = 0;
+ }
+ else if (_gone != 0)
+ _gone = 0;
+ }
+ }
+ else if (++_gone == (std::numeric_limits::max() / 2))
+ {
+ // timeout occured, normalize the _gone count
+ // this may occur if many calls to wait with a timeout are made and
+ // no call to notify_* is made
+ res = WaitForSingleObject(reinterpret_cast(_gate), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ _blocked -= _gone;
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0);
+ assert(res);
+ _gone = 0;
+ }
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+
+ if (was_waiting == 1)
+ {
+ for (/**/ ; was_gone; --was_gone)
+ {
+ // better now than spurious later
+ res = WaitForSingleObject(reinterpret_cast(_queue), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ }
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0);
+ assert(res);
+ }
+ }
+
+ bool condition::do_timed_wait(const xtime& xt)
+ {
+ unsigned milliseconds;
+ to_duration(xt, milliseconds);
+
+ int res = WaitForSingleObject(reinterpret_cast(_queue), milliseconds);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+
+ bool ret = (res == WAIT_OBJECT_0);
+
+ unsigned was_waiting=0;
+ unsigned was_gone=0;
+
+ res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ was_waiting = _waiting;
+ was_gone = _gone;
+ if (was_waiting != 0)
+ {
+ if (!ret) // timeout
+ {
+ if (_blocked != 0)
+ --_blocked;
+ else
+ ++_gone; // count spurious wakeups
+ }
+ if (--_waiting == 0)
+ {
+ if (_blocked != 0)
+ {
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0); // open _gate
+ assert(res);
+ was_waiting = 0;
+ }
+ else if (_gone != 0)
+ _gone = 0;
+ }
+ }
+ else if (++_gone == (std::numeric_limits::max() / 2))
+ {
+ // timeout occured, normalize the _gone count
+ // this may occur if many calls to wait with a timeout are made and
+ // no call to notify_* is made
+ res = WaitForSingleObject(reinterpret_cast(_gate), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ _blocked -= _gone;
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0);
+ assert(res);
+ _gone = 0;
+ }
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+
+ if (was_waiting == 1)
+ {
+ for (/**/ ; was_gone; --was_gone)
+ {
+ // better now than spurious later
+ res = WaitForSingleObject(reinterpret_cast(_queue), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ }
+ res = ReleaseSemaphore(reinterpret_cast(_gate), 1, 0);
+ assert(res);
+ }
+
+ return ret;
+ }
+#elif defined(BOOST_HAS_PTHREADS)
+ condition::condition()
+ {
+ int res = pthread_cond_init(&_cond, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::condition : failure to construct");
+ }
+
+ condition::~condition()
+ {
+ int res = pthread_cond_destroy(&_cond);
+ assert(res == 0);
+ }
+
+ void condition::notify_one()
+ {
+ int res = pthread_cond_signal(&_cond);
+ assert(res == 0);
+ }
+
+ void condition::notify_all()
+ {
+ int res = pthread_cond_broadcast(&_cond);
+ assert(res == 0);
+ }
+
+ void condition::do_wait(pthread_mutex_t* pmutex)
+ {
+ int res = pthread_cond_wait(&_cond, pmutex);
+ assert(res == 0);
+ }
+
+ bool condition::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
+ {
+ timespec ts;
+ to_timespec(xt, ts);
+
+ int res = pthread_cond_timedwait(&_cond, pmutex, &ts);
+ assert(res == 0 || res == ETIMEDOUT);
+
+ return res != ETIMEDOUT;
+ }
+#endif
+} // namespace boost
diff --git a/src/mutex.cpp b/src/mutex.cpp
new file mode 100644
index 00000000..a8eca5f8
--- /dev/null
+++ b/src/mutex.cpp
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "timeconv.inl"
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+# include
+#elif defined(BOOST_HAS_PTHREADS)
+# include
+#endif
+
+/*
+ * Hack around various namespace challenged compilers
+ */
+#ifdef BOOST_NO_STDC_NAMESPACE
+namespace std {
+ using ::clock_t;
+ using ::clock;
+} // namespace std
+#endif
+
+namespace boost
+{
+#if defined(BOOST_HAS_WINTHREADS)
+ mutex::mutex()
+ {
+ _mutex = reinterpret_cast(CreateMutex(0, 0, 0));
+ assert(_mutex);
+
+ if (!_mutex)
+ throw std::runtime_error("boost::mutex : failure to construct");
+ }
+
+ mutex::~mutex()
+ {
+ int res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void mutex::do_lock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ }
+
+ void mutex::do_unlock()
+ {
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void mutex::do_lock(cv_state& state)
+ {
+ do_lock();
+ }
+
+ void mutex::do_unlock(cv_state& state)
+ {
+ do_unlock();
+ }
+
+ try_mutex::try_mutex()
+ {
+ _mutex = reinterpret_cast(CreateMutex(0, 0, 0));
+ assert(_mutex);
+
+ if (!_mutex)
+ throw std::runtime_error("boost::try_mutex : failure to construct");
+ }
+
+ try_mutex::~try_mutex()
+ {
+ int res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void try_mutex::do_lock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ }
+
+ bool try_mutex::do_trylock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), 0);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+ return res == WAIT_OBJECT_0;
+ }
+
+ void try_mutex::do_unlock()
+ {
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void try_mutex::do_lock(cv_state& state)
+ {
+ do_lock();
+ }
+
+ void try_mutex::do_unlock(cv_state& state)
+ {
+ do_unlock();
+ }
+
+ timed_mutex::timed_mutex()
+ {
+ _mutex = reinterpret_cast(CreateMutex(0, 0, 0));
+ assert(_mutex);
+
+ if (!_mutex)
+ throw std::runtime_error("boost::timed_mutex : failure to construct");
+ }
+
+ timed_mutex::~timed_mutex()
+ {
+ int res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void timed_mutex::do_lock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ }
+
+ bool timed_mutex::do_trylock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), 0);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+ return res == WAIT_OBJECT_0;
+ }
+
+ bool timed_mutex::do_timedlock(const xtime& xt)
+ {
+ unsigned milliseconds;
+ to_duration(xt, milliseconds);
+
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), milliseconds);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+ return res == WAIT_OBJECT_0;
+ }
+
+ void timed_mutex::do_unlock()
+ {
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void timed_mutex::do_lock(cv_state& state)
+ {
+ do_lock();
+ }
+
+ void timed_mutex::do_unlock(cv_state& state)
+ {
+ do_unlock();
+ }
+#elif defined(BOOST_HAS_PTHREADS)
+ mutex::mutex()
+ {
+ int res = pthread_mutex_init(&_mutex, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::mutex : failure to construct");
+ }
+
+ mutex::~mutex()
+ {
+ int res = pthread_mutex_destroy(&_mutex);
+ assert(res == 0);
+ }
+
+ void mutex::do_lock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ if (res == EDEADLK) throw lock_error();
+ assert(res == 0);
+ }
+
+ void mutex::do_unlock()
+ {
+ int res = pthread_mutex_unlock(&_mutex);
+ if (res == EPERM) throw lock_error();
+ assert(res == 0);
+ }
+
+ void mutex::do_lock(cv_state& state)
+ {
+ }
+
+ void mutex::do_unlock(cv_state& state)
+ {
+ state.pmutex = &_mutex;
+ }
+
+ try_mutex::try_mutex()
+ {
+ int res = pthread_mutex_init(&_mutex, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::try_mutex : failure to construct");
+ }
+
+ try_mutex::~try_mutex()
+ {
+ int res = pthread_mutex_destroy(&_mutex);
+ assert(res == 0);
+ }
+
+ void try_mutex::do_lock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ if (res == EDEADLK) throw lock_error();
+ assert(res == 0);
+ }
+
+ bool try_mutex::do_trylock()
+ {
+ int res = pthread_mutex_trylock(&_mutex);
+ if (res == EDEADLK) throw lock_error();
+ assert(res == 0 || res == EBUSY);
+ return res == 0;
+ }
+
+ void try_mutex::do_unlock()
+ {
+ int res = pthread_mutex_unlock(&_mutex);
+ if (res == EPERM) throw lock_error();
+ assert(res == 0);
+ }
+
+ void try_mutex::do_lock(cv_state& state)
+ {
+ }
+
+ void try_mutex::do_unlock(cv_state& state)
+ {
+ state.pmutex = &_mutex;
+ }
+
+ timed_mutex::timed_mutex()
+ : _locked(false)
+ {
+ int res = pthread_mutex_init(&_mutex, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::timed_mutex : failure to construct");
+
+ res = pthread_cond_init(&_cond, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::timed_mutex : failure to construct");
+ }
+
+ timed_mutex::~timed_mutex()
+ {
+ assert(!_locked);
+ int res = pthread_mutex_destroy(&_mutex);
+ assert(res == 0);
+
+ res = pthread_cond_destroy(&_cond);
+ assert(res == 0);
+ }
+
+ void timed_mutex::do_lock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ while (_locked)
+ {
+ res = pthread_cond_wait(&_cond, &_mutex);
+ assert(res == 0);
+ }
+
+ assert(!_locked);
+ _locked = true;
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+
+ bool timed_mutex::do_trylock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ bool ret = false;
+ if (!_locked)
+ {
+ _locked = true;
+ ret = true;
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return ret;
+ }
+
+ bool timed_mutex::do_timedlock(const xtime& xt)
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ timespec ts;
+ to_timespec(xt, ts);
+
+ while (_locked)
+ {
+ res = pthread_cond_timedwait(&_cond, &_mutex, &ts);
+ assert(res == 0 || res == ETIMEDOUT);
+
+ if (res == ETIMEDOUT)
+ break;
+ }
+
+ bool ret = false;
+ if (!_locked)
+ {
+ _locked = true;
+ ret = true;
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return ret;
+ }
+
+ void timed_mutex::do_unlock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ assert(_locked);
+ _locked = false;
+
+ res = pthread_cond_signal(&_cond);
+ assert(res == 0);
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+
+ void timed_mutex::do_lock(cv_state& state)
+ {
+ int res;
+ while (_locked)
+ {
+ res = pthread_cond_wait(&_cond, &_mutex);
+ assert(res == 0);
+ }
+
+ assert(!_locked);
+ _locked = true;
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+
+ void timed_mutex::do_unlock(cv_state& state)
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ assert(_locked);
+ _locked = false;
+
+ res = pthread_cond_signal(&_cond);
+ assert(res == 0);
+
+ state.pmutex = &_mutex;
+ }
+#endif
+} // namespace boost
diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp
new file mode 100644
index 00000000..6e15f47d
--- /dev/null
+++ b/src/recursive_mutex.cpp
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "timeconv.inl"
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+# include
+#elif defined(BOOST_HAS_PTHREADS)
+# include
+#endif
+
+/*
+ * Hack around various namespace challenged compilers
+ */
+#ifdef BOOST_NO_STDC_NAMESPACE
+namespace std {
+ using ::clock_t;
+ using ::clock;
+} // namespace std
+#endif
+
+namespace boost {
+#if defined(BOOST_HAS_WINTHREADS)
+ recursive_mutex::recursive_mutex()
+ : _count(0)
+ {
+ _mutex = reinterpret_cast(CreateMutex(0, 0, 0));
+ assert(_mutex);
+
+ if (!_mutex)
+ throw std::runtime_error("boost::recursive_mutex : failure to construct");
+ }
+
+ recursive_mutex::~recursive_mutex()
+ {
+ int res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void recursive_mutex::do_lock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ if (++_count > 1)
+ {
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ }
+
+ void recursive_mutex::do_unlock()
+ {
+ if (--_count == 0)
+ {
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ }
+
+ void recursive_mutex::do_lock(cv_state& state)
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ _count = state;
+ }
+
+ void recursive_mutex::do_unlock(cv_state& state)
+ {
+ state = _count;
+ _count = 0;
+
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ recursive_try_mutex::recursive_try_mutex()
+ : _count(0)
+ {
+ _mutex = reinterpret_cast(CreateMutex(0, 0, 0));
+ assert(_mutex);
+
+ if (!_mutex)
+ throw std::runtime_error("boost::recursive_try_mutex : failure to construct");
+ }
+
+ recursive_try_mutex::~recursive_try_mutex()
+ {
+ int res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void recursive_try_mutex::do_lock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ if (++_count > 1)
+ {
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ }
+
+ bool recursive_try_mutex::do_trylock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), 0);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+
+ if (res == WAIT_OBJECT_0)
+ {
+ if (+++_count > 1)
+ {
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void recursive_try_mutex::do_unlock()
+ {
+ if (--_count == 0)
+ {
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ }
+
+ void recursive_try_mutex::do_lock(cv_state& state)
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ _count = state;
+ }
+
+ void recursive_try_mutex::do_unlock(cv_state& state)
+ {
+ state = _count;
+ _count = 0;
+
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ recursive_timed_mutex::recursive_timed_mutex()
+ : _count(0)
+ {
+ _mutex = reinterpret_cast(CreateMutex(0, 0, 0));
+ assert(_mutex);
+
+ if (!_mutex)
+ throw std::runtime_error("boost::recursive_timed_mutex : failure to construct");
+ }
+
+ recursive_timed_mutex::~recursive_timed_mutex()
+ {
+ int res = CloseHandle(reinterpret_cast(_mutex));
+ assert(res);
+ }
+
+ void recursive_timed_mutex::do_lock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ if (++_count > 1)
+ {
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ }
+
+ bool recursive_timed_mutex::do_trylock()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), 0);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+
+ if (res == WAIT_OBJECT_0)
+ {
+ if (+++_count > 1)
+ {
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
+ {
+ unsigned milliseconds;
+ to_duration(xt, milliseconds);
+
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), milliseconds);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+
+ if (res == WAIT_OBJECT_0)
+ {
+ if (+++_count > 1)
+ {
+ res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void recursive_timed_mutex::do_unlock()
+ {
+ if (--_count == 0)
+ {
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+ }
+
+ void recursive_timed_mutex::do_lock(cv_state& state)
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_mutex), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+
+ _count = state;
+ }
+
+ void recursive_timed_mutex::do_unlock(cv_state& state)
+ {
+ state = _count;
+ _count = 0;
+
+ int res = ReleaseMutex(reinterpret_cast(_mutex));
+ assert(res);
+ }
+#elif defined(BOOST_HAS_PTHREADS)
+ recursive_mutex::recursive_mutex()
+ : _count(0)
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ , _valid_id(false)
+# endif
+ {
+ pthread_mutexattr_t attr;
+ int res = pthread_mutexattr_init(&attr);
+ assert(res == 0);
+
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ assert(res == 0);
+# endif
+
+ res = pthread_mutex_init(&_mutex, &attr);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::recursive_mutex : failure to construct");
+
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ res = pthread_cond_init(&_unlocked, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::recursive_mutex : failure to construct");
+# endif
+ }
+
+ recursive_mutex::~recursive_mutex()
+ {
+ int res = pthread_mutex_destroy(&_mutex);
+ assert(res == 0);
+
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ res = pthread_cond_destroy(&_unlocked);
+ assert(res == 0);
+# endif
+ }
+
+ void recursive_mutex::do_lock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ if (++_count > 1)
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+# else
+ pthread_t tid = pthread_self();
+ if (_valid_id && pthread_equal(_thread_id, tid))
+ ++_count;
+ else
+ {
+ while (_valid_id)
+ {
+ res = pthread_cond_wait(&_unlocked, &_mutex);
+ assert(res == 0);
+ }
+
+ _thread_id = tid;
+ _valid_id = true;
+ _count = 1;
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+# endif
+ }
+
+ void recursive_mutex::do_unlock()
+ {
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ if (--_count == 0)
+ {
+ int res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+# else
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ pthread_t tid = pthread_self();
+ if (_valid_id && !pthread_equal(_thread_id, tid))
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ throw lock_error();
+ }
+
+ if (--_count == 0)
+ {
+ assert(_valid_id);
+ _valid_id = false;
+
+ res = pthread_cond_signal(&_unlocked);
+ assert(res == 0);
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+# endif
+ }
+
+ void recursive_mutex::do_lock(cv_state& state)
+ {
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ _count = state.count;
+# else
+ int res;
+
+ while (_valid_id)
+ {
+ res = pthread_cond_wait(&_unlocked, &_mutex);
+ assert(res == 0);
+ }
+
+ _thread_id = pthread_self();
+ _valid_id = true;
+ _count = state.count;
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+# endif
+ }
+
+ void recursive_mutex::do_unlock(cv_state& state)
+ {
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ assert(_valid_id);
+ _valid_id = false;
+
+ res = pthread_cond_signal(&_unlocked);
+ assert(res == 0);
+# endif
+
+ state.pmutex = &_mutex;
+ state.count = _count;
+ }
+
+ recursive_try_mutex::recursive_try_mutex()
+ : _count(0)
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ , _valid_id(false)
+# endif
+ {
+ pthread_mutexattr_t attr;
+ int res = pthread_mutexattr_init(&attr);
+ assert(res == 0);
+
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ assert(res == 0);
+# endif
+
+ res = pthread_mutex_init(&_mutex, &attr);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::recursive_try_mutex : failure to construct");
+
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ res = pthread_cond_init(&_unlocked, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::recursive_try_mutex : failure to construct");
+# endif
+ }
+
+ recursive_try_mutex::~recursive_try_mutex()
+ {
+ int res = pthread_mutex_destroy(&_mutex);
+ assert(res == 0);
+
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ res = pthread_cond_destroy(&_unlocked);
+ assert(res == 0);
+# endif
+ }
+
+ void recursive_try_mutex::do_lock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ if (++_count > 1)
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+# else
+ pthread_t tid = pthread_self();
+ if (_valid_id && pthread_equal(_thread_id, tid))
+ ++_count;
+ else
+ {
+ while (_valid_id)
+ {
+ res = pthread_cond_wait(&_unlocked, &_mutex);
+ assert(res == 0);
+ }
+
+ _thread_id = tid;
+ _valid_id = true;
+ _count = 1;
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+# endif
+ }
+
+ bool recursive_try_mutex::do_trylock()
+ {
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ int res = pthread_mutex_trylock(&_mutex);
+ assert(res == 0);
+
+ if (res == 0)
+ {
+ if (++_count > 1)
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+ return true;
+ }
+
+ return false;
+# else
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ bool ret = false;
+ pthread_t tid = pthread_self();
+ if (_valid_id && pthread_equal(_thread_id, tid))
+ {
+ ++_count;
+ ret = true;
+ }
+ else if (!_valid_id)
+ {
+ _thread_id = tid;
+ _valid_id = true;
+ _count = 1;
+ ret = true;
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return ret;
+# endif
+ }
+
+ void recursive_try_mutex::do_unlock()
+ {
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ if (--_count == 0)
+ {
+ int res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+# else
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ pthread_t tid = pthread_self();
+ if (_valid_id && !pthread_equal(_thread_id, tid))
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ throw lock_error();
+ }
+
+ if (--_count == 0)
+ {
+ assert(_valid_id);
+ _valid_id = false;
+
+ res = pthread_cond_signal(&_unlocked);
+ assert(res == 0);
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+# endif
+ }
+
+ void recursive_try_mutex::do_lock(cv_state& state)
+ {
+# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ _count = state.count;
+# else
+ int res;
+
+ while (_valid_id)
+ {
+ res = pthread_cond_wait(&_unlocked, &_mutex);
+ assert(res == 0);
+ }
+
+ _thread_id = pthread_self();
+ _valid_id = true;
+ _count = state.count;
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+# endif
+ }
+
+ void recursive_try_mutex::do_unlock(cv_state& state)
+ {
+# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ assert(_valid_id);
+ _valid_id = false;
+
+ res = pthread_cond_signal(&_unlocked);
+ assert(res == 0);
+# endif
+
+ state.pmutex = &_mutex;
+ state.count = _count;
+ }
+
+ recursive_timed_mutex::recursive_timed_mutex()
+ : _valid_id(false), _count(0)
+ {
+ int res = pthread_mutex_init(&_mutex, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::recursive_timed_mutex : failure to construct");
+
+ res = pthread_cond_init(&_unlocked, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::recursive_timed_mutex : failure to construct");
+ }
+
+ recursive_timed_mutex::~recursive_timed_mutex()
+ {
+ int res = pthread_mutex_destroy(&_mutex);
+ assert(res == 0);
+
+ res = pthread_cond_destroy(&_unlocked);
+ assert(res == 0);
+ }
+
+ void recursive_timed_mutex::do_lock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ pthread_t tid = pthread_self();
+ if (_valid_id && pthread_equal(_thread_id, tid))
+ ++_count;
+ else
+ {
+ while (_valid_id)
+ {
+ res = pthread_cond_wait(&_unlocked, &_mutex);
+ assert(res == 0);
+ }
+
+ _thread_id = tid;
+ _valid_id = true;
+ _count = 1;
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+
+ bool recursive_timed_mutex::do_trylock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ bool ret = false;
+ pthread_t tid = pthread_self();
+ if (_valid_id && pthread_equal(_thread_id, tid))
+ {
+ ++_count;
+ ret = true;
+ }
+ else if (!_valid_id)
+ {
+ _thread_id = tid;
+ _valid_id = true;
+ _count = 1;
+ ret = true;
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return ret;
+ }
+
+ bool recursive_timed_mutex::do_timedlock(const xtime& xt)
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ bool ret = false;
+ pthread_t tid = pthread_self();
+ if (_valid_id && pthread_equal(_thread_id, tid))
+ {
+ ++_count;
+ ret = true;
+ }
+ else
+ {
+ timespec ts;
+ to_timespec(xt, ts);
+
+ while (_valid_id)
+ {
+ res = pthread_cond_timedwait(&_unlocked, &_mutex, &ts);
+ if (res == ETIMEDOUT)
+ break;
+ assert(res == 0);
+ }
+
+ if (!_valid_id)
+ {
+ _thread_id = tid;
+ _valid_id = true;
+ _count = 1;
+ ret = true;
+ }
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return ret;
+ }
+
+ void recursive_timed_mutex::do_unlock()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ pthread_t tid = pthread_self();
+ if (_valid_id && !pthread_equal(_thread_id, tid))
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ throw lock_error();
+ }
+
+ if (--_count == 0)
+ {
+ assert(_valid_id);
+ _valid_id = false;
+
+ res = pthread_cond_signal(&_unlocked);
+ assert(res == 0);
+ }
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+
+ void recursive_timed_mutex::do_lock(cv_state& state)
+ {
+ int res;
+
+ while (_valid_id)
+ {
+ res = pthread_cond_wait(&_unlocked, &_mutex);
+ assert(res == 0);
+ }
+
+ _thread_id = pthread_self();
+ _valid_id = true;
+ _count = state.count;
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+
+ void recursive_timed_mutex::do_unlock(cv_state& state)
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ assert(_valid_id);
+ _valid_id = false;
+
+ res = pthread_cond_signal(&_unlocked);
+ assert(res == 0);
+
+ state.pmutex = &_mutex;
+ state.count = _count;
+ }
+#endif
+} // namespace boost
diff --git a/src/semaphore.cpp b/src/semaphore.cpp
new file mode 100644
index 00000000..3d9173e4
--- /dev/null
+++ b/src/semaphore.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ * 22 May 01 Modified to use xtime for time outs.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include "timeconv.inl"
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+#elif defined(BOOST_HAS_PTHREADS)
+# include
+# include
+# include
+#endif
+
+/*
+ * Hack around various namespace challenged compilers
+ */
+#ifdef BOOST_NO_STDC_NAMESPACE
+namespace std {
+ using ::clock_t;
+ using ::clock;
+} // namespace std
+#endif
+
+namespace boost {
+#if defined(BOOST_HAS_WINTHREADS)
+ semaphore::semaphore(unsigned count, unsigned max)
+ {
+ if (static_cast(max) <= 0)
+ max = std::numeric_limits::max();
+
+ _sema = reinterpret_cast(CreateSemaphore(0, count, max, 0));
+ assert(_sema != 0);
+
+ if (!_sema)
+ throw std::runtime_error("boost::semaphore : failure to construct");
+ }
+
+ semaphore::~semaphore()
+ {
+ int res = CloseHandle(reinterpret_cast(_sema));
+ assert(res);
+ }
+
+ bool semaphore::up(unsigned count, unsigned* prev)
+ {
+ long p;
+ bool ret = !!ReleaseSemaphore(reinterpret_cast(_sema), count, &p);
+ assert(ret || GetLastError() == ERROR_TOO_MANY_POSTS);
+
+ if (prev)
+ *prev = p;
+
+ return ret;
+ }
+
+ void semaphore::down()
+ {
+ int res = WaitForSingleObject(reinterpret_cast(_sema), INFINITE);
+ assert(res == WAIT_OBJECT_0);
+ }
+
+ bool semaphore::down(const xtime& xt)
+ {
+ unsigned milliseconds;
+ to_duration(xt, milliseconds);
+ int res = WaitForSingleObject(reinterpret_cast(_sema), milliseconds);
+ assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
+ return res == WAIT_OBJECT_0;
+ }
+#elif defined(BOOST_HAS_PTHREADS)
+ semaphore::semaphore(unsigned count, unsigned max)
+ : _available(count), _max(max ? max : std::numeric_limits::max())
+ {
+ int res = pthread_mutex_init(&_mutex, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::semaphore : failure to construct");
+
+ res = pthread_cond_init(&_cond, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::semaphore : failure to construct");
+ }
+
+ semaphore::~semaphore()
+ {
+ int res = pthread_mutex_destroy(&_mutex);
+ assert(res == 0);
+
+ res = pthread_cond_destroy(&_cond);
+ assert(res == 0);
+ }
+
+ bool semaphore::up(unsigned count, unsigned* prev)
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ if (prev)
+ *prev = _available;
+
+ if (_available + count > _max)
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return false;
+ }
+
+ _available += count;
+
+ res = pthread_cond_broadcast(&_cond);
+ assert(res == 0);
+
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return true;
+ }
+
+ void semaphore::down()
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ while (_available == 0)
+ {
+ res = pthread_cond_wait(&_cond, &_mutex);
+ assert(res == 0);
+ }
+
+ _available--;
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ }
+
+ bool semaphore::down(const xtime& xt)
+ {
+ int res = pthread_mutex_lock(&_mutex);
+ assert(res == 0);
+
+ timespec ts;
+ to_timespec(xt, ts);
+
+ while (_available == 0)
+ {
+ res = pthread_cond_timedwait(&_cond, &_mutex, &ts);
+ assert(res == 0 || res == ETIMEDOUT);
+
+ if (res == ETIMEDOUT)
+ {
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return false;
+ }
+ }
+
+ _available--;
+ res = pthread_mutex_unlock(&_mutex);
+ assert(res == 0);
+ return true;
+ }
+#endif
+} // namespace boost
diff --git a/src/thread.cpp b/src/thread.cpp
new file mode 100644
index 00000000..1042f439
--- /dev/null
+++ b/src/thread.cpp
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ * 1 Jun 01 Added boost::thread initial implementation.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+# include
+#elif defined(BOOST_HAS_PTHREADS)
+# include
+#endif
+
+#include "timeconv.inl"
+
+namespace
+{
+ class thread_counter
+ {
+ public:
+ thread_counter() : _threads(0) { }
+
+ void start()
+ {
+ boost::mutex::lock lock(_mutex);
+ ++_threads;
+ }
+
+ void stop()
+ {
+ boost::mutex::lock lock(_mutex);
+ if (--_threads == 0)
+ _cond.notify_all();
+ }
+
+ void wait()
+ {
+ boost::mutex::lock lock(_mutex);
+ while (_threads != 0)
+ _cond.wait(lock);
+ }
+
+ private:
+ unsigned long _threads;
+ boost::mutex _mutex;
+ boost::condition _cond;
+ };
+
+ thread_counter threads;
+ boost::tss tss_state;
+}
+
+namespace boost
+{
+ namespace detail
+ {
+ class thread_state
+ {
+ enum
+ {
+ creating,
+ created,
+ started,
+ finished
+ };
+
+ public:
+ thread_state();
+ ~thread_state();
+
+ void add_ref();
+ void release();
+ bool is_alive();
+ void join();
+
+#if defined(BOOST_HAS_WINTHREADS)
+ static unsigned __stdcall thread_proc(void* param);
+#elif defined(BOOST_HAS_PTHREADS)
+ static void* thread_proc(void* param);
+#endif
+
+ static thread_state* create(const boost::detail::threadfunc& func, void* param);
+
+ private:
+ unsigned long _refs;
+ mutex _mutex;
+ condition _cond;
+ int _state;
+ threadfunc _func;
+ void* _param;
+#if defined(BOOST_HAS_WINTHREADS)
+ HANDLE _thread;
+#elif defined(BOOST_HAS_PTHREADS)
+ pthread_t _thread;
+#endif
+
+ // This line illustrate the internal compiler error encountered on MSVC
+// boost::function _function;
+ };
+
+ thread_state::thread_state()
+ : _state(creating), _refs(2) // Both created thread and creating thread own at first
+ {
+ }
+
+ thread_state::~thread_state()
+ {
+ if (_state == finished)
+ {
+#if defined(BOOST_HAS_WINTHREADS)
+ int res = CloseHandle(_thread);
+ assert(res);
+#elif defined(BOOST_HAS_PTHREADS)
+ int res = pthread_detach(_thread);
+ assert(res == 0);
+#endif
+ }
+ }
+
+ void thread_state::add_ref()
+ {
+ mutex::lock lock(_mutex);
+ ++_refs;
+ }
+
+ void thread_state::release()
+ {
+ bool del = false;
+ {
+ mutex::lock lock(_mutex);
+ del = (--_refs == 0);
+ }
+ if (del) delete this;
+ }
+
+ bool thread_state::is_alive()
+ {
+ mutex::lock lock(_mutex);
+ return _state == started;
+ }
+
+ void thread_state::join()
+ {
+ mutex::lock lock(_mutex);
+ while (_state != finished)
+ _cond.wait(lock);
+ }
+
+#if defined(BOOST_HAS_WINTHREADS)
+ unsigned __stdcall thread_state::thread_proc(void* param)
+#elif defined(BOOST_HAS_PTHREADS)
+ void* thread_state::thread_proc(void* param)
+#endif
+ {
+ thread_state* state = static_cast(param);
+ assert(state);
+
+ tss_state.set(state);
+
+ {
+ mutex::lock lock(state->_mutex);
+
+ while (state->_state != created)
+ state->_cond.wait(lock);
+
+ state->_state = started;
+ state->_cond.notify_all();
+ threads.start();
+ }
+
+ try
+ {
+ state->_func(state->_param);
+ }
+ catch (...)
+ {
+ }
+
+ {
+ mutex::lock lock(state->_mutex);
+ state->_state = finished;
+ state->_cond.notify_all();
+ }
+
+ state->release();
+ threads.stop();
+
+ return 0;
+ }
+
+ thread_state* thread_state::create(const boost::detail::threadfunc& func, void* param)
+ {
+ thread_state* state = new thread_state();
+ mutex::lock lock(state->_mutex);
+
+ assert(func);
+ state->_func = func;
+ state->_param = param;
+
+#if defined(BOOST_HAS_WINTHREADS)
+ unsigned id;
+ state->_thread = (HANDLE)_beginthreadex(0, 0, &thread_proc, state, 0, &id);
+ assert(state->_thread);
+
+ if (state->_thread == 0)
+ {
+ delete state;
+ return 0;
+ }
+#elif defined(BOOST_HAS_PTHREADS)
+ int res = pthread_create(&state->_thread, 0, &thread_proc, state);
+ assert(res == 0);
+
+ if (res != 0)
+ {
+ delete state;
+ return 0;
+ }
+#endif
+
+ state->_state = created;
+ state->_cond.notify_all();
+
+ while (state->_state != started)
+ state->_cond.wait(lock);
+
+ return state;
+ }
+ }
+
+ lock_error::lock_error() : std::runtime_error("thread lock error")
+ {
+ }
+
+ thread::thread(const thread& other)
+ : _state(other._state)
+ {
+ if (_state)
+ _state->add_ref();
+ }
+
+ thread::~thread()
+ {
+ if (_state)
+ _state->release();
+ }
+
+ bool thread::is_alive() const
+ {
+ if (_state)
+ return _state->is_alive();
+ return false;
+ }
+
+ void thread::join()
+ {
+ if (_state)
+ _state->join();
+ }
+
+ thread thread::create(const detail::threadfunc& func, void* param)
+ {
+ thread temp;
+ temp._state = detail::thread_state::create(func, param);
+ return temp;
+ }
+
+ thread thread::self()
+ {
+ thread temp;
+ temp._state = static_cast(tss_state.get());
+ if (temp._state)
+ temp._state->add_ref();
+ return temp;
+ }
+
+ void thread::join_all()
+ {
+ threads.wait();
+ }
+
+ void thread::sleep(const xtime& xt)
+ {
+#if defined(BOOST_HAS_WINTHREADS)
+ unsigned milliseconds;
+ to_duration(xt, milliseconds);
+ Sleep(milliseconds);
+#elif defined(BOOST_HAS_PTHREADS)
+# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
+ timespec ts;
+ to_timespec(xt, ts);
+ int res = pthread_delay_np(&ts);
+ assert(res == 0);
+# elif defined(BOOST_HAS_NANOSLEEP)
+ timespec ts;
+ to_timespec(xt, ts);
+ nanosleep(&ts, 0);
+# else
+ boost::semaphore sema;
+ sema.down(xt);
+# endif
+#endif
+ }
+
+ void thread::yield()
+ {
+#if defined(BOOST_HAS_WINTHREADS)
+ Sleep(0);
+#elif defined(BOOST_HAS_PTHREADS)
+# if defined(BOOST_HAS_SCHED_YIELD)
+ int res = sched_yield();
+ assert(res == 0);
+# elif defined(BOOST_HAS_PTHREAD_YIELD)
+ int res = pthread_yield();
+ assert(res == 0);
+# else
+ xtime xt;
+ xtime_get(&xt, boost::TIME_UTC);
+ sleep(xt);
+# endif
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/timeconv.inl b/src/timeconv.inl
new file mode 100644
index 00000000..a5a9518d
--- /dev/null
+++ b/src/timeconv.inl
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 1 Jun 01 Initial creation.
+ */
+
+namespace {
+ const unsigned MILLISECONDS_PER_SECOND = 1000;
+ const unsigned NANOSECONDS_PER_SECOND = 1000000000;
+ const unsigned NANOSECONDS_PER_MILLISECOND = 1000000;
+
+ inline void to_time(unsigned milliseconds, boost::xtime& xt)
+ {
+ int res = boost::xtime_get(&xt, boost::TIME_UTC);
+ assert(res == boost::TIME_UTC);
+
+ xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
+ xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND);
+
+ if (xt.nsec > NANOSECONDS_PER_SECOND)
+ {
+ ++xt.sec;
+ xt.nsec -= NANOSECONDS_PER_SECOND;
+ }
+ }
+
+#if defined(BOOST_HAS_PTHREADS)
+ inline void to_timespec(const boost::xtime& xt, timespec& ts)
+ {
+ ts.tv_sec = static_cast(xt.sec);
+ ts.tv_nsec = static_cast(xt.nsec);
+ }
+
+ inline void to_time(unsigned milliseconds, timespec& ts)
+ {
+ boost::xtime xt;
+ to_time(milliseconds, xt);
+ to_timespec(xt, ts);
+ }
+#endif
+
+ inline void to_duration(const boost::xtime& xt, unsigned& milliseconds)
+ {
+ boost::xtime cur;
+ int res = boost::xtime_get(&cur, boost::TIME_UTC);
+ assert(res == boost::TIME_UTC);
+
+ if (xt.sec < cur.sec || (xt.sec == cur.sec && xt.nsec < cur.nsec))
+ milliseconds = 0;
+ else
+ {
+ milliseconds = ((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
+ (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2))
+ / NANOSECONDS_PER_MILLISECOND);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/tss.cpp b/src/tss.cpp
new file mode 100644
index 00000000..01f3cf37
--- /dev/null
+++ b/src/tss.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 6 Jun 01 Initial version.
+ */
+
+#include
+#include
+
+#if defined(BOOST_HAS_WINTHREADS)
+# include
+#endif
+
+#include
+
+namespace boost
+{
+#if defined(BOOST_HAS_WINTHREADS)
+ tss::tss()
+ {
+ _key = TlsAlloc();
+ assert(_key != 0xFFFFFFFF);
+
+ if (_key == 0xFFFFFFFF)
+ throw std::runtime_error("boost::tss : failure to construct");
+ }
+
+ tss::~tss()
+ {
+ int res = TlsFree(_key);
+ assert(res);
+ }
+
+ void* tss::get() const
+ {
+ return TlsGetValue(_key);
+ }
+
+ bool tss::set(void* value)
+ {
+ return TlsSetValue(_key, value);
+ }
+#elif defined(BOOST_HAS_PTHREADS)
+ tss::tss()
+ {
+ int res = pthread_key_create(&_key, 0);
+ assert(res == 0);
+
+ if (res != 0)
+ throw std::runtime_error("boost::tss : failure to construct");
+ }
+
+ tss::~tss()
+ {
+ int res = pthread_key_delete(_key);
+ assert(res == 0);
+ }
+
+ void* tss::get() const
+ {
+ return pthread_getspecific(_key);
+ }
+
+ bool tss::set(void* value)
+ {
+ return pthread_setspecific(_key, value) == 0;
+ }
+#endif
+}
\ No newline at end of file
diff --git a/src/xtime.cpp b/src/xtime.cpp
new file mode 100644
index 00000000..23f31108
--- /dev/null
+++ b/src/xtime.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2001
+ * William E. Kempf
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. William E. Kempf makes no representations
+ * about the suitability of this software for any purpose.
+ * It is provided "as is" without express or implied warranty.
+ *
+ * Revision History (excluding minor changes for specific compilers)
+ * 8 Feb 01 Initial version.
+ */
+
+#include
+#include
+
+#if defined(BOOST_HAS_FTIME)
+# include
+#endif
+
+namespace boost {
+ int xtime_get(struct xtime* xtp, int clock_type)
+ {
+ if (clock_type == TIME_UTC)
+ {
+#if defined(BOOST_HAS_FTIME)
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ const __int64 TIMESPEC_TO_FILETIME_OFFSET = ((__int64)27111902 << 32) + (__int64)3577643008;
+ xtp->sec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
+ xtp->nsec = (int)((*(__int64*)&ft - TIMESPEC_TO_FILETIME_OFFSET -
+ ((__int64)xtp->sec * (__int64)10000000)) * 100);
+ return clock_type;
+#elif defined(BOOST_HAS_GETTIMEOFDAY)
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ xtp->sec = tv.tv_sec;
+ xtp->nsec = tv.tv_usec * 1000;
+ return clock_type;
+#elif defined(BOOST_HAS_CLOCK_GETTIME)
+ timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ xtp->sec = ts.tv_sec;
+ xtp->nsec = ts.tv_nsec;
+ return clock_type;
+#else
+ return 0;
+#endif
+ }
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/test/Jamfile b/test/Jamfile
index e69de29b..765fb691 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -0,0 +1,11 @@
+SubDir TOP test ;
+
+exe test_thread
+ : test_thread.cpp
+ ../src/threads
+ ## Requirements ##
+ : ..
+ multi
+ ## default-BUILD ##
+ : debug release
+ ;
diff --git a/test/test_thread.cpp b/test/test_thread.cpp
new file mode 100644
index 00000000..80b8a19c
--- /dev/null
+++ b/test/test_thread.cpp
@@ -0,0 +1,426 @@
+#include
+#include
+#include
+#include
+#include
+//#include
+#include
+
+#define BOOST_INCLUDE_MAIN
+#include
+
+#include
+
+template
+void test_lock(M* dummy=0)
+{
+ typedef M mutex_type;
+ typedef typename M::lock lock_type;
+
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ lock_type lock(mutex, false);
+ BOOST_TEST(!lock);
+ }
+ lock_type lock(mutex);
+ BOOST_TEST(lock);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::xtime xt;
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+
+ // Test the lock and the mutex with condition variables.
+ // No one is going to notify this condition variable. We expect to
+ // time out.
+ BOOST_TEST(condition.timed_wait(lock, xt) == false);
+ BOOST_TEST(lock);
+
+ // Test the lock and unlock methods.
+ lock.unlock();
+ BOOST_TEST(!lock);
+ lock.lock();
+ BOOST_TEST(lock);
+}
+
+template
+void test_trylock(M* dummy=0)
+{
+ typedef M mutex_type;
+ typedef typename M::trylock trylock_type;
+
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ trylock_type lock(mutex);
+ BOOST_TEST(lock);
+ }
+ {
+ trylock_type lock(mutex, false);
+ BOOST_TEST(!lock);
+ }
+ trylock_type lock(mutex, true);
+ BOOST_TEST(lock);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::xtime xt;
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+
+ // Test the lock and the mutex with condition variables.
+ // No one is going to notify this condition variable. We expect to
+ // time out.
+ BOOST_TEST(condition.timed_wait(lock, xt) == false);
+ BOOST_TEST(lock);
+
+ // Test the lock, unlock and trylock methods.
+ lock.unlock();
+ BOOST_TEST(!lock);
+ lock.lock();
+ BOOST_TEST(lock);
+ lock.unlock();
+ BOOST_TEST(!lock);
+ BOOST_TEST(lock.try_lock());
+ BOOST_TEST(lock);
+}
+
+template
+void test_timedlock(M* dummy=0)
+{
+ typedef M mutex_type;
+ typedef typename M::timedlock timedlock_type;
+
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ // Construct and initialize an xtime for a fast time out.
+ boost::xtime xt;
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+
+ timedlock_type lock(mutex, xt);
+ BOOST_TEST(lock);
+ }
+ {
+ timedlock_type lock(mutex, false);
+ BOOST_TEST(!lock);
+ }
+ timedlock_type lock(mutex, true);
+ BOOST_TEST(lock);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::xtime xt;
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+
+ // Test the lock and the mutex with condition variables.
+ // No one is going to notify this condition variable. We expect to
+ // time out.
+ BOOST_TEST(condition.timed_wait(lock, xt) == false);
+ BOOST_TEST(lock);
+
+ // Test the lock, unlock and timedlock methods.
+ lock.unlock();
+ BOOST_TEST(!lock);
+ lock.lock();
+ BOOST_TEST(lock);
+ lock.unlock();
+ BOOST_TEST(!lock);
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+ BOOST_TEST(lock.timed_lock(xt));
+}
+
+void test_mutex()
+{
+ typedef boost::mutex mutex;
+ test_lock();
+}
+
+void test_try_mutex()
+{
+ typedef boost::try_mutex mutex;
+ test_lock();
+ test_trylock();
+}
+
+void test_timed_mutex()
+{
+ typedef boost::timed_mutex mutex;
+ test_lock();
+ test_trylock();
+ test_timedlock();
+}
+
+void test_recursive_mutex()
+{
+ typedef boost::recursive_mutex mutex;
+ test_lock();
+ mutex mx;
+ mutex::lock lock1(mx);
+ mutex::lock lock2(mx);
+}
+
+void test_recursive_try_mutex()
+{
+ typedef boost::recursive_try_mutex mutex;
+ test_lock();
+ test_trylock();
+ mutex mx;
+ mutex::lock lock1(mx);
+ mutex::lock lock2(mx);
+}
+
+void test_recursive_timed_mutex()
+{
+ typedef boost::recursive_timed_mutex mutex;
+ test_lock();
+ test_trylock();
+ test_timedlock();
+ mutex mx;
+ mutex::lock lock1(mx);
+ mutex::lock lock2(mx);
+}
+
+struct condition_test_data
+{
+ condition_test_data() : notified(0), awoken(0) { }
+
+ boost::mutex mutex;
+ boost::condition condition;
+ int notified;
+ int awoken;
+};
+
+void condition_test_thread(void* param)
+{
+ condition_test_data* data = static_cast(param);
+ boost::mutex::lock lock(data->mutex);
+ BOOST_TEST(lock);
+ while (!(data->notified > 0))
+ data->condition.wait(lock);
+ BOOST_TEST(lock);
+ data->awoken++;
+}
+
+void test_condition_notify_one()
+{
+ condition_test_data data;
+
+ boost::thread::create(&condition_test_thread, &data);
+
+ {
+ boost::mutex::lock lock(data.mutex);
+ BOOST_TEST(lock);
+ data.notified++;
+ data.condition.notify_one();
+ }
+
+ boost::thread::join_all();
+ BOOST_TEST(data.awoken == 1);
+}
+
+void test_condition_notify_all()
+{
+ const int NUMTHREADS = 5;
+ condition_test_data data;
+
+ for (int i = 0; i < NUMTHREADS; ++i)
+ boost::thread::create(&condition_test_thread, &data);
+
+ {
+ boost::mutex::lock lock(data.mutex);
+ BOOST_TEST(lock);
+ data.notified++;
+ data.condition.notify_all();
+ }
+
+ boost::thread::join_all();
+ BOOST_TEST(data.awoken == NUMTHREADS);
+}
+
+struct cond_predicate
+{
+ cond_predicate(int& var, int val) : _var(var), _val(val) { }
+
+ bool operator()() { return _var == _val; }
+
+ int& _var;
+ int _val;
+};
+
+void condition_test_waits(void* param)
+{
+ condition_test_data* data = static_cast(param);
+
+ boost::mutex::lock lock(data->mutex);
+ BOOST_TEST(lock);
+
+ // Test wait.
+ while (data->notified != 1)
+ data->condition.wait(lock);
+ BOOST_TEST(lock);
+ BOOST_TEST(data->notified == 1);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate wait.
+ data->condition.wait(lock, cond_predicate(data->notified, 2));
+ BOOST_TEST(lock);
+ BOOST_TEST(data->notified == 2);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test timed_wait.
+ boost::xtime xt;
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+ while (data->notified != 3)
+ data->condition.timed_wait(lock, xt);
+ BOOST_TEST(lock);
+ BOOST_TEST(data->notified == 3);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate timed_wait.
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.sec += 2;
+ BOOST_TEST(data->condition.timed_wait(lock, xt, cond_predicate(data->notified, 4)));
+ BOOST_TEST(lock);
+ BOOST_TEST(data->notified == 4);
+ data->awoken++;
+}
+
+void test_condition_waits()
+{
+ condition_test_data data;
+
+ boost::thread::create(&condition_test_waits, &data);
+
+ boost::xtime xt;
+
+ {
+ boost::mutex::lock lock(data.mutex);
+ BOOST_TEST(lock);
+
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt);
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 1)
+ data.condition.wait(lock);
+ BOOST_TEST(data.awoken == 1);
+
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt);
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 2)
+ data.condition.wait(lock);
+ BOOST_TEST(data.awoken == 2);
+
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt);
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 3)
+ data.condition.wait(lock);
+ BOOST_TEST(data.awoken == 3);
+ }
+
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt);
+ data.notified++;
+ data.condition.notify_one();
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.sec += 1;
+ boost::thread::sleep(xt);
+ boost::thread::join_all();
+ BOOST_TEST(data.awoken == 4);
+}
+
+void test_condition()
+{
+ test_condition_notify_one();
+ test_condition_notify_all();
+ test_condition_waits();
+}
+
+void test_semaphore()
+{
+ boost::xtime xt;
+ unsigned val;
+ boost::semaphore sema(0, 1);
+
+ BOOST_TEST(sema.up(1, &val));
+ BOOST_TEST(val == 0);
+ BOOST_TEST(!sema.up());
+
+ sema.down();
+ BOOST_TEST(sema.up());
+
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+ BOOST_TEST(sema.down(xt));
+ BOOST_TEST(boost::xtime_get(&xt, boost::TIME_UTC) == boost::TIME_UTC);
+ xt.nsec += 100000000;
+ BOOST_TEST(!sema.down(xt));
+}
+
+/*void test_atomic_t()
+{
+ boost::atomic_t atomic;
+ BOOST_TEST(boost::increment(atomic) > 0);
+ BOOST_TEST(boost::decrement(atomic) == 0);
+ BOOST_TEST(boost::swap(atomic, 10) == 0);
+ BOOST_TEST(boost::swap(atomic, 0) == 10);
+ BOOST_TEST(boost::compare_swap(atomic, 20, 10) == 0);
+ BOOST_TEST(boost::compare_swap(atomic, 20, 0) == 0);
+ BOOST_TEST(boost::read(atomic) == 20);
+}*/
+
+void test_tss_thread(void*)
+{
+ static boost::tss value;
+ value.set(new int(0));
+
+ for (int i=0; i<1000; ++i)
+ {
+ int* pn = static_cast(value.get());
+ BOOST_TEST(*pn == i);
+ ++*pn;
+ boost::thread::yield();
+ }
+}
+
+void test_tss()
+{
+ for (int i=0; i<5; ++i)
+ boost::thread::create(&test_tss_thread);
+ boost::thread::join_all();
+}
+
+int test_main(int, char*[])
+{
+ test_mutex();
+ test_try_mutex();
+ test_timed_mutex();
+ test_recursive_mutex();
+ test_recursive_try_mutex();
+ test_recursive_timed_mutex();
+ test_condition();
+ test_semaphore();
+ test_tss();
+ return 0;
+}
diff --git a/test/test_thread.dsp b/test/test_thread.dsp
new file mode 100644
index 00000000..89652912
--- /dev/null
+++ b/test/test_thread.dsp
@@ -0,0 +1,166 @@
+# Microsoft Developer Studio Project File - Name="test_thread" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_thread - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_thread.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_thread.mak" CFG="test_thread - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_thread - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_thread - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_thread - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "test_thread_Release"
+# PROP Intermediate_Dir "test_thread_Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib pthreadvce.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "test_thread - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "test_thread_Debug"
+# PROP Intermediate_Dir "test_thread_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib pthreadvce.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_thread - Win32 Release"
+# Name "test_thread - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\src\atomic.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\condition.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\mutex.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\recursive_mutex.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\semaphore.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\test_thread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\thread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\xtime.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\boost\thread\atomic.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\thread\condition.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\config.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\thread\mutex.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\thread\recursive_mutex.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\thread\semaphore.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\thread\thread.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\thread\xlock.hpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\boost\thread\xtime.hpp
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/test/test_thread.dsw b/test/test_thread.dsw
new file mode 100644
index 00000000..a1376e86
--- /dev/null
+++ b/test/test_thread.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "test_thread"=.\test_thread.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+