mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
20 Commits
svn-branch
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83d2bb6716 | ||
|
|
b937d909e9 | ||
|
|
2918732481 | ||
|
|
5a4d5ddb9d | ||
|
|
55afcf678d | ||
|
|
16c7cf9b5e | ||
|
|
432bd29c1c | ||
|
|
a87914ef23 | ||
|
|
041530a953 | ||
|
|
9d4c55161a | ||
|
|
a706d1df00 | ||
|
|
b15b2e666f | ||
|
|
5d4678364e | ||
|
|
9590526430 | ||
|
|
1c6dfda83c | ||
|
|
a8be12940e | ||
|
|
4b5046366b | ||
|
|
a0fff90c26 | ||
|
|
94d9b1b288 | ||
|
|
a8daedac5e |
@@ -14,13 +14,13 @@ project boost/thread
|
||||
;
|
||||
|
||||
CPP_SOURCES =
|
||||
barrier
|
||||
condition
|
||||
# barrier
|
||||
# condition
|
||||
exceptions
|
||||
mutex
|
||||
once
|
||||
recursive_mutex
|
||||
read_write_mutex
|
||||
# mutex
|
||||
# once
|
||||
# recursive_mutex
|
||||
# read_write_mutex
|
||||
thread
|
||||
tss_hooks
|
||||
tss_dll
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
# Copyright (C) 2001-2003
|
||||
# William E. Kempf
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Additional configuration variables used:
|
||||
# 1. PTW32_DIR and PTW32_LIB may be used on Win32 platforms to specify that
|
||||
# a version of Boost.Threads should be built that uses the
|
||||
# the pthreads-win32 library instead of the Win32 native threading APIs.
|
||||
# This feature is mostly used for testing and it's generally recommended
|
||||
# that you use the Win32 native threading libraries instead.
|
||||
#
|
||||
# PTW32_Dir should be set to the installation path of the
|
||||
# pthreads-win32 library and PTW32_LIB should be set to the name of the
|
||||
# library variant to link against (see the pthreads-win32 documentation).
|
||||
# Example: jam -sPTW32_DIR="c:\pthreads-win32" -sPTW32_LIB="pthreadVCE.lib"
|
||||
# Alternately, environment variables having the names PTW32_DIR and PTW32_LIB
|
||||
# can be set instead of passing these values on the command line.
|
||||
#
|
||||
# In either case, libraries having the names boost_thread_ptw32<tags>.dll
|
||||
# and libboost_thread_ptw32<tags>.lib will be built
|
||||
# in addition to the usual boost_thread<tags>.dll and
|
||||
# libboost_thread<tags>.lib. Link with one of the ptw32 versions
|
||||
# of the Boost.Threads libraries to use the version of Boost.Threads
|
||||
# that is implemented using pthreads-win32 (you will need to #define
|
||||
# BOOST_THREAD_NO_LIB or BOOST_ALL_NO_LIB to disable auto-linking
|
||||
# if your platform supports auto-linking in order to prevent
|
||||
# your build from attempting to link to two different versions of
|
||||
# the Boost.Threads library).
|
||||
|
||||
# Do some OS-specific setup
|
||||
{
|
||||
#thread library name
|
||||
boost_thread_lib_name = boost_thread ;
|
||||
|
||||
#thread library name with "pthreads-win32" library
|
||||
boost_thread_lib_name_ptw32 = boost_thread_ptw32 ;
|
||||
|
||||
if $(NT)
|
||||
{
|
||||
if $(PTW32_DIR)
|
||||
{
|
||||
if $(PTW32_LIB)
|
||||
{
|
||||
boost_thread_lib_settings_ptw32 =
|
||||
<define>BOOST_HAS_PTHREADS
|
||||
<define>PtW32NoCatchWarn
|
||||
<include>$(PTW32_DIR)/pre-built/include
|
||||
<library-file>$(PTW32_DIR)/pre-built/lib/$(PTW32_LIB)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template thread_base
|
||||
: ## sources ##
|
||||
: ## requirements ##
|
||||
<sysinclude>$(BOOST_ROOT)
|
||||
<threading>multi
|
||||
<borland><*><cxxflags>-w-8004
|
||||
<borland><*><cxxflags>-w-8057
|
||||
: ## default build ##
|
||||
;
|
||||
}
|
||||
Binary file not shown.
@@ -63,6 +63,11 @@ last-revision="$Date$">
|
||||
Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor
|
||||
Perrin, Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William
|
||||
Kempf.</para>
|
||||
<para>
|
||||
As of February 2006 Anthony Williams and Roland Schwarz took over maintainance
|
||||
and further development of the library after it has been in an orphaned state
|
||||
for a rather long period of time.
|
||||
</para>
|
||||
<para>Apologies for anyone inadvertently missed.</para>
|
||||
</section>
|
||||
|
||||
|
||||
131
doc/build.xml
131
doc/build.xml
@@ -5,6 +5,7 @@
|
||||
%thread.entities;
|
||||
]>
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
|
||||
Copyright (c) 2007 Roland Schwarz
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
@@ -25,38 +26,112 @@
|
||||
</para>
|
||||
<section id="thread.build.building">
|
||||
<title>Building the &Boost.Thread; Libraries</title>
|
||||
<para>
|
||||
To build the &Boost.Thread; libraries using &Boost.Build;, simply change to the
|
||||
directory <emphasis>boost_root</emphasis>/libs/thread/build and execute the command:
|
||||
<programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis></programlisting>
|
||||
This will create the debug and the release builds of the &Boost.Thread; library.
|
||||
<note>Invoking the above command in <emphasis>boost_root</emphasis> will build all of
|
||||
the Boost distribution, including &Boost.Thread;.</note>
|
||||
</para>
|
||||
<para>
|
||||
The Jamfile supplied with &Boost.Thread; produces a dynamic link library named
|
||||
<emphasis>boost_thread{build-specific-tags}.{extension}</emphasis>, where the build-specific
|
||||
tags indicate the toolset used to build the library, whether it's a debug or release
|
||||
build, what version of Boost was used, etc.; and the extension is the appropriate extension
|
||||
for a dynamic link library for the platform for which &Boost.Thread; is being built.
|
||||
For instance, a debug library built for Win32 with VC++ 7.1 using Boost 1.31 would
|
||||
be named <emphasis>boost_thread-vc71-mt-gd-1_31.dll</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
The source files that are used to create the &Boost.Thread; library
|
||||
are all of the *.cpp files found in <emphasis>boost_root</emphasis>/libs/thread/src.
|
||||
These need to be built with the compiler's and linker's multi-threading support enabled.
|
||||
If you want to create your own build solution you'll have to follow these same
|
||||
guidelines. One of the most frequently reported problems when trying to do this
|
||||
occurs from not enabling the compiler's and linker's support for multi-threading.
|
||||
</para>
|
||||
<para>
|
||||
Building the &Boost.Thread; Library depends on how you intend to use it. You have several options:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
Using as a <link linkend="thread.build.precompiled">precompiled</link> library, possibly
|
||||
with auto-linking, or for use from within an IDE.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Use from a <link linkend="thread.build.bjam">&Boost.Build;</link> project.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Using in <link linkend="thread.build.source">source</link> form.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<section id="thread.build.precompiled">
|
||||
<title>Precompiled</title>
|
||||
<para>
|
||||
Using the &Boost.Thread; library in precompiled form is the way to go if you want to
|
||||
install the library to a standard place, from where your linker is able to resolve code
|
||||
in binary form. You also will want this option if compile time is a concern. Multiple
|
||||
variants are available, for different toolsets and build variants (debug/release).
|
||||
The library files are named <emphasis>{lead}boost_thread{build-specific-tags}.{extension}</emphasis>,
|
||||
where the build-specific-tags indicate the toolset used to build the library, whether it's
|
||||
a debug or release build, what version of &Boost; was used, etc.; and the lead and extension
|
||||
are the appropriate extensions for a dynamic link library or static library for the platform
|
||||
for which &Boost.Thread; is being built.
|
||||
For instance, a debug build of the dynamic library built for Win32 with VC++ 7.1 using Boost 1.34 would
|
||||
be named <emphasis>boost_thread-vc71-mt-gd-1_34.dll</emphasis>.
|
||||
More information on this should be available from the &Boost.Build; documentation.
|
||||
</para>
|
||||
<para>
|
||||
Building should be possible with the default configuration. If you are running into problems,
|
||||
it might be wise to adjust your local settings of &Boost.Build; though. Typically you will
|
||||
need to get your user-config.jam file to reflect your environment, i.e. used toolsets. Please
|
||||
refer to the &Boost.Build; documentation to learn how to do this.
|
||||
</para>
|
||||
<para>
|
||||
To create the libraries you need to open a command shell and change to the
|
||||
<emphasis>boost_root</emphasis> directory. From there you give the command
|
||||
<programlisting>bjam --toolset=<emphasis>mytoolset</emphasis> stage --with-thread</programlisting>
|
||||
Replace <emphasis>mytoolset</emphasis> with the name of your toolset, e.g. msvc-7.1 .
|
||||
This will compile and put the libraries into the <emphasis>stage</emphasis> directory which is just below the
|
||||
<emphasis>boost_root</emphasis> directory. &Boost.Build; by default will generate static and
|
||||
dynamic variants for debug and release.
|
||||
</para>
|
||||
<note>
|
||||
Invoking the above command without the --with-thread switch &Boost.Build; will build all of
|
||||
the Boost distribution, including &Boost.Thread;.
|
||||
</note>
|
||||
<para>
|
||||
The next step is to copy your libraries to a place where your linker is able to pick them up.
|
||||
It is also quite possible to leave them in the stage directory and instruct your IDE to take them
|
||||
from there.
|
||||
</para>
|
||||
<para>
|
||||
In your IDE you then need to add <emphasis>boost_root</emphasis>/boost to the paths where the compiler
|
||||
expects to find files to be included. For toolsets that support <emphasis>auto-linking</emphasis>
|
||||
it is not necessary to explicitly specify the name of the library to link against, it is sufficient
|
||||
to specify the path of the stage directory. Typically this is true on Windows. For gcc you need
|
||||
to specify the exact library name (including all the tags). Please don't forget that threading
|
||||
support must be turned on to be able to use the library. You should be able now to build your
|
||||
project from the IDE.
|
||||
</para>
|
||||
</section>
|
||||
<section id="thread.build.bjam">
|
||||
<title>&Boost.Build; Project</title>
|
||||
<para>
|
||||
If you have decided to use &Boost.Build; as a build environment for your application, you simply
|
||||
need to add a single line to your <emphasis>Jamroot</emphasis> file:
|
||||
<programlisting>use-project /boost : {path-to-boost-root} ;</programlisting>
|
||||
where <emphasis>{path-to-boost-root}</emphasis> needs to be replaced with the location of
|
||||
your copy of the boost tree.
|
||||
Later when you specify a component that needs to link against &Boost.Thread; you specify this
|
||||
as e.g.:
|
||||
<programlisting>exe myapp : {myappsources} /boost//thread ;</programlisting>
|
||||
and you are done.
|
||||
</para>
|
||||
</section>
|
||||
<section id="thread.build.source">
|
||||
<title>Source Form</title>
|
||||
<para>
|
||||
Of course it is also possible to use the &Boost.Thread; library in source form.
|
||||
First you need to specify the <emphasis>boost_root</emphasis>/boost directory as
|
||||
a path where your compiler expects to find files to include. It is not easy
|
||||
to isolate the &Boost.Thread; include files from the rest of the boost
|
||||
library though. You would also need to isolate every include file that the thread
|
||||
library depends on. Next you need to copy the files from
|
||||
<emphasis>boost_root</emphasis>/libs/thread/src to your project and instruct your
|
||||
build system to compile them together with your project. Please look into the
|
||||
<emphasis>Jamfile</emphasis> in <emphasis>boost_root</emphasis>/libs/thread/build
|
||||
to find out which compiler options and defines you will need to get a clean compile.
|
||||
Using the boost library in this way is the least recommended, and should only be
|
||||
considered if avoiding dependency on &Boost.Build; is a requirement. Even if so
|
||||
it might be a better option to use the library in it's precompiled form.
|
||||
Precompiled downloads are available from the boost consulting web site, or as
|
||||
part of most linux distributions.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="thread.build.testing">
|
||||
<title>Testing the &Boost.Thread; Libraries</title>
|
||||
<para>
|
||||
To test the &Boost.Thread; libraries using &Boost.Build;, simply change to the
|
||||
directory <emphasis>boost_root</emphasis>/libs/thread/test and execute the command:
|
||||
<programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis> test</programlisting>
|
||||
To test the &Boost.Thread; libraries using &Boost.Build;, simply change to the
|
||||
directory <emphasis>boost_root</emphasis>/libs/thread/test and execute the command:
|
||||
<programlisting>bjam --toolset=<emphasis>mytoolset</emphasis> test</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -18,7 +18,17 @@
|
||||
which allow only one thread at a time to access a resource when it is
|
||||
being modified (the "Write" part of Read/Write), but allows multiple threads
|
||||
to access a resource when it is only being referenced (the "Read" part of
|
||||
Read/Write).</para>
|
||||
Read/Write).</para>
|
||||
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
|
||||
<section id="thread.concepts.mutexes">
|
||||
<title>Mutexes</title>
|
||||
@@ -739,13 +749,18 @@
|
||||
|
||||
<section id="thread.concepts.read-write-mutexes">
|
||||
<title>Read/Write Mutexes</title>
|
||||
<note>Since the read/write mutex and related classes are new,
|
||||
both interface and implementation are liable to change
|
||||
in future releases of &Boost.Thread;.
|
||||
The lock concepts and lock promotion and demotion in particular
|
||||
are still under discussion and very likely to change.</note>
|
||||
<note> Unfortunately it turned out that the current implementation has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
|
||||
<para>A read/write mutex (short for reader/writer mutual-exclusion) object
|
||||
<para>A read/write mutex (short for reader/writer mutual-exclusion) object
|
||||
is used to serialize access to a resource shared between multiple
|
||||
threads, where multiple "readers" can share simultaneous access, but
|
||||
"writers" require exclusive access. The
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
|
||||
-->
|
||||
<!ENTITY Boost "<emphasis role='bold'>Boost</emphasis>">
|
||||
<!ENTITY Boost.Thread "<emphasis role='bold'>Boost.Thread</emphasis>">
|
||||
<!ENTITY Boost.Build "<emphasis role='bold'>Boost.Build</emphasis>">
|
||||
<!ENTITY cite.AndrewsSchneider83 "<citation><xref
|
||||
|
||||
@@ -65,25 +65,23 @@ void init()
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
boost::call_once(once, &init);
|
||||
}</programlisting>
|
||||
</para></description>
|
||||
|
||||
<parameter name="func">
|
||||
<paramtype>void (*func)()</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="flag">
|
||||
<paramtype>once_flag&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<requires>The function <code>func</code> shall not throw
|
||||
exceptions.</requires>
|
||||
|
||||
<parameter name="func">
|
||||
<paramtype>Function func</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>As if (in an atomic fashion):
|
||||
<code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
|
||||
<code>if (flag == BOOST_ONCE_INIT) func();</code>. If <code>func()</code> throws an exception, it shall be as if this
|
||||
thread never invoked <code>call_once</code></effects>
|
||||
|
||||
<postconditions><code>flag != BOOST_ONCE_INIT</code>
|
||||
<postconditions><code>flag != BOOST_ONCE_INIT</code> unless <code>func()</code> throws an exception.
|
||||
</postconditions>
|
||||
</function>
|
||||
</namespace>
|
||||
|
||||
@@ -37,6 +37,16 @@
|
||||
<purpose>
|
||||
<para>The <classname>read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.</para>
|
||||
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
@@ -160,6 +170,16 @@
|
||||
<purpose>
|
||||
<para>The <classname>try_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.</para>
|
||||
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
@@ -302,6 +322,16 @@
|
||||
<purpose>
|
||||
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
|
||||
<link linkend="thread.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.</para>
|
||||
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
|
||||
some serious problems. So it was decided not to put this implementation into
|
||||
release grade code. Also discussions on the mailing list led to the
|
||||
conclusion that the current concepts need to be rethought. In particular
|
||||
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
|
||||
Inter-Class Scheduling Policies</link> are deemed unnecessary.
|
||||
There seems to be common belief that a fair scheme suffices.
|
||||
The following documentation has been retained however, to give
|
||||
readers of this document the opportunity to study the original design.
|
||||
</note>
|
||||
</purpose>
|
||||
|
||||
<description>
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
<xi:include href="mutex-ref.xml"/>
|
||||
<xi:include href="once-ref.xml"/>
|
||||
<xi:include href="recursive_mutex-ref.xml"/>
|
||||
<!--
|
||||
The read_write_mutex is held back from release, since the
|
||||
implementation suffers from a serious, yet unresolved bug.
|
||||
The implementation is likely to appear in a reworked
|
||||
form in the next release.
|
||||
-->
|
||||
<xi:include href="read_write_mutex-ref.xml"/>
|
||||
<xi:include href="thread-ref.xml"/>
|
||||
<xi:include href="tss-ref.xml"/>
|
||||
|
||||
@@ -10,7 +10,63 @@
|
||||
-->
|
||||
<section id="thread.release_notes" last-revision="$Date$">
|
||||
<title>Release Notes</title>
|
||||
<section id="thread.release_notes.boost_1_32_0">
|
||||
<section id="thread.release_notes.boost_1_34_0">
|
||||
<title>Boost 1.34.0</title>
|
||||
|
||||
<section id="thread.release_notes.boost_1_34_0.change_log.maintainance">
|
||||
<title>New team of maintainers</title>
|
||||
|
||||
<para>
|
||||
Since the original author William E. Kempf no longer is available to
|
||||
maintain the &Boost.Thread; library, a new team has been formed
|
||||
in an attempt to continue the work on &Boost.Thread;.
|
||||
Fortunately William E. Kempf has given
|
||||
<ulink url="http://lists.boost.org/Archives/boost/2006/09/110143.php">
|
||||
permission </ulink>
|
||||
to use his work under the boost license.
|
||||
</para>
|
||||
<para>
|
||||
The team currently consists of
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
Anthony Williams, for the Win32 platform,
|
||||
</listitem>
|
||||
<listitem>
|
||||
Roland Schwarz, for the linux platform, and various "housekeeping" tasks.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
Volunteers for other platforms are welcome!
|
||||
</para>
|
||||
<para>
|
||||
As the &Boost.Thread; was kind of orphaned over the last release, this release
|
||||
attempts to fix the known bugs. Upcoming releases will bring in new things.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="thread.release_notes.boost_1_34_0.change_log.read_write_mutex">
|
||||
<title>read_write_mutex still broken</title>
|
||||
|
||||
<para>
|
||||
<note>
|
||||
It has been decided not to release the Read/Write Mutex, since the current
|
||||
implementation suffers from a serious bug. The documentation of the concepts
|
||||
has been included though, giving the interested reader an opportunity to study the
|
||||
original concepts. Please refer to the following links if you are interested
|
||||
which problems led to the decision to held back this mutex type.The issue
|
||||
has been discovered before 1.33 was released and the code has
|
||||
been omitted from that release. A reworked mutex is expected to appear in 1.35.
|
||||
Also see:
|
||||
<ulink url="http://lists.boost.org/Archives/boost/2005/08/92307.php">
|
||||
read_write_mutex bug</ulink>
|
||||
and
|
||||
<ulink url="http://lists.boost.org/Archives/boost/2005/09/93180.php">
|
||||
read_write_mutex fundamentally broken in 1.33</ulink>
|
||||
</note>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
<section id="thread.release_notes.boost_1_32_0">
|
||||
<title>Boost 1.32.0</title>
|
||||
|
||||
<section id="thread.release_notes.boost_1_32_0.change_log.documentation">
|
||||
|
||||
@@ -264,20 +264,7 @@
|
||||
<effects>Calls <code>join()</code> on each of the managed
|
||||
<classname>thread</classname> objects.</effects>
|
||||
</method>
|
||||
</method-group>
|
||||
|
||||
<method-group name="capacity">
|
||||
|
||||
<method name="size" cv="const">
|
||||
<type>int</type>
|
||||
|
||||
<returns>the number of <classname>thread</classname>
|
||||
objects in the group
|
||||
</returns>
|
||||
|
||||
</method>
|
||||
|
||||
</method-group>
|
||||
</method-group>
|
||||
</class>
|
||||
</namespace>
|
||||
</header>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,33 +12,47 @@
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class BOOST_THREAD_DECL barrier
|
||||
namespace boost
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count);
|
||||
~barrier();
|
||||
|
||||
bool wait();
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::invalid_argument("count cannot be zero.");
|
||||
}
|
||||
|
||||
bool wait()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
{
|
||||
m_generation++;
|
||||
m_count = m_threshold;
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
condition m_cond;
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
condition m_cond;
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -1,200 +1,10 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#ifndef BOOST_THREAD_CONDITION_HPP
|
||||
#define BOOST_THREAD_CONDITION_HPP
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
#ifndef BOOST_CONDITION_WEK070601_HPP
|
||||
#define BOOST_CONDITION_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
namespace detail {
|
||||
|
||||
class BOOST_THREAD_DECL condition_impl : private noncopyable
|
||||
namespace boost
|
||||
{
|
||||
friend class condition;
|
||||
typedef condition_variable_any condition;
|
||||
}
|
||||
|
||||
public:
|
||||
condition_impl();
|
||||
~condition_impl();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
void enter_wait();
|
||||
void do_wait();
|
||||
bool do_timed_wait(const xtime& xt);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
void do_wait(pthread_mutex_t* pmutex);
|
||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_gate;
|
||||
void* m_queue;
|
||||
void* m_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_cond_t m_condition;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPSemaphoreID m_gate;
|
||||
MPSemaphoreID m_queue;
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class condition : private noncopyable
|
||||
{
|
||||
public:
|
||||
condition() { }
|
||||
~condition() { }
|
||||
|
||||
void notify_one() { m_impl.notify_one(); }
|
||||
void notify_all() { m_impl.notify_all(); }
|
||||
|
||||
template <typename L>
|
||||
void wait(L& lock)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
void wait(L& lock, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L>
|
||||
bool timed_wait(L& lock, const xtime& xt)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
return do_timed_wait(lock.m_mutex, xt);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
bool timed_wait(L& lock, const xtime& xt, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
{
|
||||
if (!do_timed_wait(lock.m_mutex, xt))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::condition_impl m_impl;
|
||||
|
||||
template <typename M>
|
||||
void do_wait(M& mutex)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
m_impl.do_wait(state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.do_wait();
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool do_timed_wait(M& mutex, const xtime& xt)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
ret = m_impl.do_timed_wait(xt, state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
ret = m_impl.do_timed_wait(xt);
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
|
||||
// difficult to use with spurious wakeups.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_CONDITION_WEK070601_HPP
|
||||
|
||||
15
include/boost/thread/condition_variable.hpp
Normal file
15
include/boost/thread/condition_variable.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
|
||||
// condition_variable.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#include BOOST_THREAD_PLATFORM(condition_variable.hpp)
|
||||
|
||||
#endif
|
||||
@@ -1,209 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_XLOCK_WEK070601_HPP
|
||||
#define BOOST_XLOCK_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class condition;
|
||||
struct xtime;
|
||||
|
||||
namespace detail { namespace thread {
|
||||
|
||||
template <typename Mutex>
|
||||
class lock_ops : private noncopyable
|
||||
{
|
||||
private:
|
||||
lock_ops() { }
|
||||
|
||||
public:
|
||||
typedef typename Mutex::cv_state lock_state;
|
||||
|
||||
static void lock(Mutex& m)
|
||||
{
|
||||
m.do_lock();
|
||||
}
|
||||
static bool trylock(Mutex& m)
|
||||
{
|
||||
return m.do_trylock();
|
||||
}
|
||||
static bool timedlock(Mutex& m, const xtime& xt)
|
||||
{
|
||||
return m.do_timedlock(xt);
|
||||
}
|
||||
static void unlock(Mutex& m)
|
||||
{
|
||||
m.do_unlock();
|
||||
}
|
||||
static void lock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_lock(state);
|
||||
}
|
||||
static void unlock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_unlock(state);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mutex>
|
||||
class scoped_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
Mutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TryMutex>
|
||||
class scoped_try_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TryMutex mutex_type;
|
||||
|
||||
explicit scoped_try_lock(TryMutex& mx)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
scoped_try_lock(TryMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_try_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TryMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TimedMutex>
|
||||
class scoped_timed_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TimedMutex mutex_type;
|
||||
|
||||
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
timed_lock(xt);
|
||||
}
|
||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_timed_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::trylock(m_mutex));
|
||||
}
|
||||
bool timed_lock(const xtime& xt)
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TimedMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_XLOCK_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed
|
||||
// some types. Added locked() methods.
|
||||
33
include/boost/thread/detail/move.hpp
Normal file
33
include/boost/thread/detail/move.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#ifndef BOOST_THREAD_MOVE_HPP
|
||||
#define BOOST_THREAD_MOVE_HPP
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<typename T>
|
||||
struct move_t
|
||||
{
|
||||
T& t;
|
||||
move_t(T& t_):
|
||||
t(t_)
|
||||
{}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
move_t<T> move(T& t)
|
||||
{
|
||||
return move_t<T>(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
72
include/boost/thread/detail/platform.hpp
Normal file
72
include/boost/thread/detail/platform.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2006 Roland Schwarz.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// This work is a reimplementation along the design and ideas
|
||||
// of William E. Kempf.
|
||||
|
||||
#ifndef BOOST_THREAD_RS06040501_HPP
|
||||
#define BOOST_THREAD_RS06040501_HPP
|
||||
|
||||
// fetch compiler and platform configuration
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
// choose platform
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define BOOST_THREAD_LINUX
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
# define BOOST_THREAD_BSD
|
||||
#elif defined(sun) || defined(__sun)
|
||||
# define BOOST_THREAD_SOLARIS
|
||||
#elif defined(__sgi)
|
||||
# define BOOST_THREAD_IRIX
|
||||
#elif defined(__hpux)
|
||||
# define BOOST_THREAD_HPUX
|
||||
#elif defined(__CYGWIN__)
|
||||
# define BOOST_THREAD_CYGWIN
|
||||
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
# define BOOST_THREAD_WIN32
|
||||
#elif defined(__BEOS__)
|
||||
# define BOOST_THREAD_BEOS
|
||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define BOOST_THREAD_MACOS
|
||||
#elif defined(__IBMCPP__) || defined(_AIX)
|
||||
# define BOOST_THREAD_AIX
|
||||
#elif defined(__amigaos__)
|
||||
# define BOOST_THREAD_AMIGAOS
|
||||
#elif defined(__QNXNTO__)
|
||||
# define BOOST_THREAD_QNXNTO
|
||||
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
|
||||
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_POSIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For every supported platform add a new entry into the dispatch table below.
|
||||
// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native
|
||||
// threading is available, the user may choose, by defining BOOST_THREAD_POSIX
|
||||
// in her source. If a platform is known to support pthreads and no native
|
||||
// port of boost_thread is available just specify "pthread" in the
|
||||
// dispatcher table. If there is no entry for a platform but pthreads is
|
||||
// available on the platform, pthread is choosen as default. If nothing is
|
||||
// available the preprocessor will fail with a diagnostic message.
|
||||
|
||||
#if defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_PPFX pthread
|
||||
#else
|
||||
# if defined(BOOST_THREAD_WIN32)
|
||||
# define BOOST_THREAD_PPFX win32
|
||||
# elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_THREAD_PPFX pthread
|
||||
# else
|
||||
# error "Sorry, no boost threads are available for this platform."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_PLATFORM(header) <boost/thread/BOOST_THREAD_PPFX/header>
|
||||
|
||||
#endif // BOOST_THREAD_RS06040501_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -35,6 +36,17 @@ private:
|
||||
int m_sys_err;
|
||||
};
|
||||
|
||||
class condition_error:
|
||||
public std::exception
|
||||
{
|
||||
public:
|
||||
const char* what() const throw()
|
||||
{
|
||||
return "Condition error";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BOOST_THREAD_DECL lock_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
|
||||
520
include/boost/thread/locks.hpp
Normal file
520
include/boost/thread/locks.hpp
Normal file
@@ -0,0 +1,520 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
#ifndef BOOST_THREAD_LOCKS_HPP
|
||||
#define BOOST_THREAD_LOCKS_HPP
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct defer_lock_t
|
||||
{};
|
||||
struct try_to_lock_t
|
||||
{};
|
||||
struct adopt_lock_t
|
||||
{};
|
||||
|
||||
const defer_lock_t defer_lock={};
|
||||
const try_to_lock_t try_to_lock={};
|
||||
const adopt_lock_t adopt_lock={};
|
||||
|
||||
template<typename Mutex>
|
||||
class shared_lock;
|
||||
|
||||
template<typename Mutex>
|
||||
class exclusive_lock;
|
||||
|
||||
template<typename Mutex>
|
||||
class upgrade_lock;
|
||||
|
||||
template<typename Mutex>
|
||||
class lock_guard
|
||||
{
|
||||
private:
|
||||
Mutex& m;
|
||||
|
||||
explicit lock_guard(lock_guard&);
|
||||
lock_guard& operator=(lock_guard&);
|
||||
public:
|
||||
explicit lock_guard(Mutex& m_):
|
||||
m(m_)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
lock_guard(Mutex& m_,adopt_lock_t):
|
||||
m(m_)
|
||||
{}
|
||||
~lock_guard()
|
||||
{
|
||||
m.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Mutex>
|
||||
class unique_lock
|
||||
{
|
||||
private:
|
||||
Mutex* m;
|
||||
bool is_locked;
|
||||
explicit unique_lock(unique_lock&);
|
||||
unique_lock& operator=(unique_lock&);
|
||||
public:
|
||||
explicit unique_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
unique_lock(Mutex& m_,adopt_lock_t):
|
||||
m(&m_),is_locked(true)
|
||||
{}
|
||||
unique_lock(Mutex& m_,defer_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{}
|
||||
unique_lock(Mutex& m_,try_to_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
unique_lock(Mutex& m_,system_time const& target_time):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
timed_lock(target_time);
|
||||
}
|
||||
unique_lock(boost::move_t<unique_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
}
|
||||
unique_lock(boost::move_t<upgrade_lock<Mutex> > other);
|
||||
|
||||
unique_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
unique_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
|
||||
{
|
||||
unique_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(unique_lock& other)
|
||||
{
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
void swap(boost::move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
std::swap(m,other->m);
|
||||
std::swap(is_locked,other->is_locked);
|
||||
}
|
||||
|
||||
~unique_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
m->unlock();
|
||||
}
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->lock();
|
||||
is_locked=true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->try_lock();
|
||||
return is_locked;
|
||||
}
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const& relative_time)
|
||||
{
|
||||
is_locked=m->timed_lock(relative_time);
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
bool timed_lock(::boost::system_time const& absolute_time)
|
||||
{
|
||||
is_locked=m->timed_lock(absolute_time);
|
||||
return is_locked;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if(!owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->unlock();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
typedef void (unique_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
return is_locked?&unique_lock::lock:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
Mutex* mutex() const
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
Mutex* release()
|
||||
{
|
||||
Mutex* const res=m;
|
||||
m=0;
|
||||
is_locked=false;
|
||||
return res;
|
||||
}
|
||||
|
||||
friend class shared_lock<Mutex>;
|
||||
friend class upgrade_lock<Mutex>;
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
class shared_lock
|
||||
{
|
||||
protected:
|
||||
Mutex* m;
|
||||
bool is_locked;
|
||||
private:
|
||||
explicit shared_lock(shared_lock&);
|
||||
shared_lock& operator=(shared_lock&);
|
||||
public:
|
||||
explicit shared_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
shared_lock(Mutex& m_,adopt_lock_t):
|
||||
m(&m_),is_locked(true)
|
||||
{}
|
||||
shared_lock(Mutex& m_,defer_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{}
|
||||
shared_lock(Mutex& m_,try_to_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
shared_lock(Mutex& m_,system_time const& target_time):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
timed_lock(target_time);
|
||||
}
|
||||
|
||||
shared_lock(boost::move_t<shared_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
}
|
||||
|
||||
shared_lock(boost::move_t<unique_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_and_lock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
shared_lock(boost::move_t<upgrade_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_upgrade_and_lock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
shared_lock& operator=(boost::move_t<shared_lock<Mutex> > other)
|
||||
{
|
||||
shared_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
shared_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
shared_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
shared_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
|
||||
{
|
||||
shared_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(shared_lock& other)
|
||||
{
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
|
||||
~shared_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
m->unlock_shared();
|
||||
}
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->lock_shared();
|
||||
is_locked=true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->try_lock_shared();
|
||||
return is_locked;
|
||||
}
|
||||
bool timed_lock(boost::system_time const& target_time)
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->timed_lock_shared(target_time);
|
||||
return is_locked;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if(!owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->unlock_shared();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
typedef void (shared_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
return is_locked?&shared_lock::lock:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
class upgrade_lock
|
||||
{
|
||||
protected:
|
||||
Mutex* m;
|
||||
bool is_locked;
|
||||
private:
|
||||
explicit upgrade_lock(upgrade_lock&);
|
||||
upgrade_lock& operator=(upgrade_lock&);
|
||||
public:
|
||||
explicit upgrade_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
upgrade_lock(Mutex& m_,bool do_lock):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
if(do_lock)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
}
|
||||
upgrade_lock(boost::move_t<upgrade_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
}
|
||||
|
||||
upgrade_lock(boost::move_t<unique_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_and_lock_upgrade();
|
||||
}
|
||||
}
|
||||
|
||||
upgrade_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
|
||||
{
|
||||
upgrade_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
upgrade_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
upgrade_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(upgrade_lock& other)
|
||||
{
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
|
||||
~upgrade_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
m->unlock_upgrade();
|
||||
}
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->lock_upgrade();
|
||||
is_locked=true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->try_lock_upgrade();
|
||||
return is_locked;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if(!owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->unlock_upgrade();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
typedef void (upgrade_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
return is_locked?&upgrade_lock::lock:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return is_locked;
|
||||
}
|
||||
friend class shared_lock<Mutex>;
|
||||
friend class unique_lock<Mutex>;
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
unique_lock<Mutex>::unique_lock(boost::move_t<upgrade_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_upgrade_and_lock();
|
||||
}
|
||||
}
|
||||
|
||||
template <class Mutex>
|
||||
class upgrade_to_unique_lock
|
||||
{
|
||||
private:
|
||||
upgrade_lock<Mutex>* source;
|
||||
unique_lock<Mutex> exclusive;
|
||||
|
||||
explicit upgrade_to_unique_lock(upgrade_to_unique_lock&);
|
||||
upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&);
|
||||
public:
|
||||
explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_):
|
||||
source(&m_),exclusive(boost::move(*source))
|
||||
{}
|
||||
~upgrade_to_unique_lock()
|
||||
{
|
||||
if(source)
|
||||
{
|
||||
*source=boost::move(exclusive);
|
||||
}
|
||||
}
|
||||
|
||||
upgrade_to_unique_lock(boost::move_t<upgrade_to_unique_lock<Mutex> > other):
|
||||
source(other->source),exclusive(boost::move(other->exclusive))
|
||||
{
|
||||
other->source=0;
|
||||
}
|
||||
|
||||
upgrade_to_unique_lock& operator=(boost::move_t<upgrade_to_unique_lock<Mutex> > other)
|
||||
{
|
||||
upgrade_to_unique_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
void swap(upgrade_to_unique_lock& other)
|
||||
{
|
||||
std::swap(source,other.source);
|
||||
exclusive.swap(other.exclusive);
|
||||
}
|
||||
typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&);
|
||||
operator bool_type() const
|
||||
{
|
||||
return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return exclusive.owns_lock();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,169 +1,15 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_MUTEX_HPP
|
||||
|
||||
// mutex.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MUTEX_WEK070601_HPP
|
||||
#define BOOST_MUTEX_WEK070601_HPP
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#include BOOST_THREAD_PLATFORM(mutex.hpp)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
class BOOST_THREAD_DECL mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
||||
|
||||
mutex();
|
||||
~mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
||||
|
||||
try_mutex();
|
||||
~try_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
||||
|
||||
timed_mutex();
|
||||
~timed_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_condition;
|
||||
bool m_locked;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
@@ -1,37 +1,23 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_ONCE_WEK080101_HPP
|
||||
#define BOOST_ONCE_WEK080101_HPP
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#include BOOST_THREAD_PLATFORM(once.hpp)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
|
||||
typedef pthread_once_t once_flag;
|
||||
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
|
||||
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
|
||||
typedef long once_flag;
|
||||
#define BOOST_ONCE_INIT 0
|
||||
namespace boost
|
||||
{
|
||||
inline void call_once(void (*func)(),once_flag& flag)
|
||||
{
|
||||
call_once(flag,func);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
|
||||
#endif // BOOST_ONCE_WEK080101_HPP
|
||||
|
||||
194
include/boost/thread/pthread/condition_variable.hpp
Normal file
194
include/boost/thread/pthread/condition_variable.hpp
Normal file
@@ -0,0 +1,194 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <limits.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <pthread.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable
|
||||
{
|
||||
private:
|
||||
pthread_cond_t cond;
|
||||
|
||||
condition_variable(condition_variable&);
|
||||
condition_variable& operator=(condition_variable&);
|
||||
public:
|
||||
condition_variable()
|
||||
{
|
||||
int const res=pthread_cond_init(&cond,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~condition_variable()
|
||||
{
|
||||
int const res=pthread_cond_destroy(&cond);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex>& m)
|
||||
{
|
||||
int const cond_res=pthread_cond_wait(&cond,m.mutex()->native_handle());
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
int const cond_res=pthread_cond_timedwait(&cond,m.mutex()->native_handle(),&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
int const res=pthread_cond_signal(&cond);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
int const res=pthread_cond_broadcast(&cond);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
};
|
||||
|
||||
class condition_variable_any
|
||||
{
|
||||
pthread_mutex_t internal_mutex;
|
||||
pthread_cond_t cond;
|
||||
|
||||
condition_variable_any(condition_variable&);
|
||||
condition_variable_any& operator=(condition_variable&);
|
||||
|
||||
public:
|
||||
condition_variable_any()
|
||||
{
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
int const destroy_res=pthread_mutex_destroy(&internal_mutex);
|
||||
BOOST_ASSERT(!destroy_res);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~condition_variable_any()
|
||||
{
|
||||
int const res=pthread_mutex_destroy(&internal_mutex);
|
||||
BOOST_ASSERT(!res);
|
||||
int const res2=pthread_cond_destroy(&cond);
|
||||
BOOST_ASSERT(!res2);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
int res=0;
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
m.unlock();
|
||||
res=pthread_cond_wait(&cond,&internal_mutex);
|
||||
}
|
||||
m.lock();
|
||||
if(res)
|
||||
{
|
||||
throw condition_error();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
int res=0;
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
m.unlock();
|
||||
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
}
|
||||
m.lock();
|
||||
if(res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
throw condition_error();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
int const res=pthread_cond_signal(&cond);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
int const res=pthread_cond_broadcast(&cond);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
205
include/boost/thread/pthread/mutex.hpp
Normal file
205
include/boost/thread/pthread/mutex.hpp
Normal file
@@ -0,0 +1,205 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
int const res=pthread_mutex_destroy(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
int const res=pthread_mutex_lock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int const res=pthread_mutex_unlock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle() const
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
#endif
|
||||
public:
|
||||
timed_mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
int const destroy_res=pthread_mutex_destroy(&m);
|
||||
BOOST_ASSERT(!destroy_res);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
#endif
|
||||
}
|
||||
~timed_mutex()
|
||||
{
|
||||
int const res=pthread_mutex_destroy(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
int const res2=pthread_cond_destroy(&cond);
|
||||
BOOST_ASSERT(!res2);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
int const res=pthread_mutex_lock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int const res=pthread_mutex_unlock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_wait(&cond,&m);
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
is_locked=false;
|
||||
int const res=pthread_cond_signal(&cond);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
74
include/boost/thread/pthread/once.hpp
Normal file
74
include/boost/thread/pthread/once.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
unsigned flag;
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT {PTHREAD_MUTEX_INITIALIZER,0}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct pthread_mutex_scoped_lock
|
||||
{
|
||||
pthread_mutex_t * mutex;
|
||||
|
||||
explicit pthread_mutex_scoped_lock(pthread_mutex_t* mutex_):
|
||||
mutex(mutex_)
|
||||
{
|
||||
int const res=pthread_mutex_lock(mutex);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
~pthread_mutex_scoped_lock()
|
||||
{
|
||||
int const res=pthread_mutex_unlock(mutex);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
long const function_complete_flag_value=0xc15730e2;
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_ATOMICS
|
||||
if(::boost::detail::interlocked_read_acquire(&flag.flag)!=function_complete_flag_value)
|
||||
{
|
||||
#endif
|
||||
detail::pthread_mutex_scoped_lock const lock(&flag.mutex);
|
||||
if(flag.flag!=function_complete_flag_value)
|
||||
{
|
||||
f();
|
||||
#ifdef BOOST_PTHREAD_HAS_ATOMICS
|
||||
::boost::detail::interlocked_write_release(&flag.flag,function_complete_flag_value);
|
||||
#else
|
||||
flag.flag=function_complete_flag_value;
|
||||
#endif
|
||||
}
|
||||
#ifdef BOOST_PTHREAD_HAS_ATOMICS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
30
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
30
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace pthread
|
||||
{
|
||||
class pthread_mutex_scoped_lock
|
||||
{
|
||||
pthread_mutex_t* m;
|
||||
public:
|
||||
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
|
||||
m(m_)
|
||||
{
|
||||
int const res=pthread_mutex_lock(m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
~pthread_mutex_scoped_lock()
|
||||
{
|
||||
int const res=pthread_mutex_unlock(m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
260
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
260
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
@@ -0,0 +1,260 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const destroy_attr_res=pthread_mutexattr_destroy(&attr);
|
||||
BOOST_ASSERT(!destroy_attr_res);
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
int const res=pthread_mutex_destroy(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
int const res=pthread_mutex_lock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int const res=pthread_mutex_unlock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
pthread_t owner;
|
||||
unsigned count;
|
||||
#endif
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
int const destroy_attr_res=pthread_mutexattr_destroy(&attr);
|
||||
BOOST_ASSERT(!destroy_attr_res);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const destroy_attr_res=pthread_mutexattr_destroy(&attr);
|
||||
BOOST_ASSERT(!destroy_attr_res);
|
||||
#else
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
int const destroy_res=pthread_mutex_destroy(&m);
|
||||
BOOST_ASSERT(!destroy_res);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
count=0;
|
||||
#endif
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
int const res=pthread_mutex_destroy(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
int const res2=pthread_cond_destroy(&cond);
|
||||
BOOST_ASSERT(!res2);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
int const res=pthread_mutex_lock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int const res=pthread_mutex_unlock(&m);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && owner==pthread_self())
|
||||
{
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_wait(&cond,&m);
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(!--count)
|
||||
{
|
||||
is_locked=false;
|
||||
}
|
||||
int const res=pthread_cond_signal(&cond);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && owner!=pthread_self())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && owner==pthread_self())
|
||||
{
|
||||
++count;
|
||||
return true;
|
||||
}
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
299
include/boost/thread/pthread/shared_mutex.hpp
Normal file
299
include/boost/thread/pthread/shared_mutex.hpp
Normal file
@@ -0,0 +1,299 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count;
|
||||
bool exclusive;
|
||||
bool upgrade;
|
||||
bool exclusive_waiting_blocked;
|
||||
};
|
||||
|
||||
|
||||
|
||||
state_data state;
|
||||
boost::mutex state_change;
|
||||
boost::condition shared_cond;
|
||||
boost::condition exclusive_cond;
|
||||
boost::condition upgrade_cond;
|
||||
|
||||
void release_waiters()
|
||||
{
|
||||
exclusive_cond.notify_one();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex()
|
||||
{
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked)
|
||||
{
|
||||
++state.shared_count;
|
||||
return;
|
||||
}
|
||||
|
||||
shared_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock_shared(system_time const& timeout)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked)
|
||||
{
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(state.upgrade)
|
||||
{
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
upgrade_cond.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return;
|
||||
}
|
||||
exclusive_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const& timeout)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
if(!exclusive_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade)
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return;
|
||||
}
|
||||
|
||||
shared_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock_upgrade(system_time const& timeout)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade)
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
--state.shared_count;
|
||||
while(true)
|
||||
{
|
||||
if(!state.shared_count)
|
||||
{
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
break;
|
||||
}
|
||||
upgrade_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
23
include/boost/thread/pthread/timespec.hpp
Normal file
23
include/boost/thread/pthread/timespec.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline struct timespec get_timespec(boost::system_time const& abs_time)
|
||||
{
|
||||
struct timespec timeout={0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
timeout.tv_sec=time_since_epoch.total_seconds();
|
||||
timeout.tv_nsec=time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second());
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,285 +0,0 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf, Michael Glassford
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// A Boost::threads implementation of a synchronization
|
||||
// primitive which can allow multiple readers or a single
|
||||
// writer to have access to a shared resource.
|
||||
|
||||
#ifndef BOOST_READ_WRITE_MUTEX_JDM030602_HPP
|
||||
#define BOOST_READ_WRITE_MUTEX_JDM030602_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
#include <boost/thread/detail/read_write_lock.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
namespace boost {
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
namespace read_write_scheduling_policy {
|
||||
enum read_write_scheduling_policy_enum
|
||||
{
|
||||
writer_priority, //Prefer writers; can starve readers
|
||||
reader_priority, //Prefer readers; can starve writers
|
||||
alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers
|
||||
alternating_single_read //Alternate readers and writers; before a writer, release only one queued reader
|
||||
};
|
||||
} // namespace read_write_scheduling_policy
|
||||
|
||||
namespace detail {
|
||||
|
||||
namespace thread {
|
||||
|
||||
// Shared implementation construct for explicit Scheduling Policies
|
||||
// This implementation is susceptible to self-deadlock, though....
|
||||
template<typename Mutex>
|
||||
struct read_write_mutex_impl
|
||||
{
|
||||
typedef Mutex mutex_type;
|
||||
typedef detail::thread::scoped_lock<Mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<Mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<Mutex> scoped_timed_lock;
|
||||
|
||||
read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__,<= 0x564)
|
||||
~read_write_mutex_impl();
|
||||
#endif
|
||||
|
||||
Mutex m_prot;
|
||||
|
||||
const read_write_scheduling_policy::read_write_scheduling_policy_enum m_sp;
|
||||
int m_state; //-1 = write lock; 0 = unlocked; >0 = read locked
|
||||
|
||||
boost::condition m_waiting_writers;
|
||||
boost::condition m_waiting_readers;
|
||||
boost::condition m_waiting_promotion;
|
||||
int m_num_waiting_writers;
|
||||
int m_num_waiting_readers;
|
||||
bool m_state_waiting_promotion;
|
||||
|
||||
int m_num_waking_writers;
|
||||
int m_num_waking_readers;
|
||||
int m_num_max_waking_writers; //Debug only
|
||||
int m_num_max_waking_readers; //Debug only
|
||||
|
||||
bool m_readers_next;
|
||||
|
||||
void do_read_lock();
|
||||
void do_write_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
bool do_try_write_lock();
|
||||
bool do_try_read_lock();
|
||||
bool do_timed_write_lock(const xtime &xt);
|
||||
bool do_timed_read_lock(const xtime &xt);
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
bool do_try_demote_to_read_lock();
|
||||
bool do_timed_demote_to_read_lock(const xtime &xt);
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
bool do_try_promote_to_write_lock();
|
||||
bool do_timed_promote_to_write_lock(const xtime &xt);
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
private:
|
||||
|
||||
bool do_demote_to_read_lock_impl();
|
||||
|
||||
enum scheduling_reason
|
||||
{
|
||||
scheduling_reason_unlock,
|
||||
scheduling_reason_timeout,
|
||||
scheduling_reason_demote
|
||||
};
|
||||
|
||||
void do_scheduling_impl(const scheduling_reason reason);
|
||||
bool do_wake_one_reader(void);
|
||||
bool do_wake_all_readers(void);
|
||||
bool do_wake_writer(void);
|
||||
bool waker_exists(void);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace thread
|
||||
|
||||
class BOOST_THREAD_DECL read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
friend class detail::thread::read_write_lock_ops<read_write_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_read_write_lock<
|
||||
read_write_mutex> scoped_read_write_lock;
|
||||
|
||||
typedef detail::thread::scoped_read_lock<
|
||||
read_write_mutex> scoped_read_lock;
|
||||
|
||||
typedef detail::thread::scoped_write_lock<
|
||||
read_write_mutex> scoped_write_lock;
|
||||
|
||||
private:
|
||||
|
||||
// Operations that will eventually be done only
|
||||
// via lock types
|
||||
void do_write_lock();
|
||||
void do_read_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
detail::thread::read_write_mutex_impl<mutex> m_impl;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL try_read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~try_read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
friend class detail::thread::read_write_lock_ops<try_read_write_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_read_write_lock<
|
||||
try_read_write_mutex> scoped_read_write_lock;
|
||||
typedef detail::thread::scoped_try_read_write_lock<
|
||||
try_read_write_mutex> scoped_try_read_write_lock;
|
||||
|
||||
typedef detail::thread::scoped_read_lock<
|
||||
try_read_write_mutex> scoped_read_lock;
|
||||
typedef detail::thread::scoped_try_read_lock<
|
||||
try_read_write_mutex> scoped_try_read_lock;
|
||||
|
||||
typedef detail::thread::scoped_write_lock<
|
||||
try_read_write_mutex> scoped_write_lock;
|
||||
typedef detail::thread::scoped_try_write_lock<
|
||||
try_read_write_mutex> scoped_try_write_lock;
|
||||
|
||||
private:
|
||||
|
||||
// Operations that will eventually be done only
|
||||
// via lock types
|
||||
void do_write_lock();
|
||||
void do_read_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
bool do_try_write_lock();
|
||||
bool do_try_read_lock();
|
||||
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
bool do_try_demote_to_read_lock();
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
bool do_try_promote_to_write_lock();
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
detail::thread::read_write_mutex_impl<try_mutex> m_impl;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL timed_read_write_mutex : private noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
|
||||
~timed_read_write_mutex();
|
||||
|
||||
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
|
||||
|
||||
friend class detail::thread::read_write_lock_ops<timed_read_write_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_read_write_lock<
|
||||
timed_read_write_mutex> scoped_read_write_lock;
|
||||
typedef detail::thread::scoped_try_read_write_lock<
|
||||
timed_read_write_mutex> scoped_try_read_write_lock;
|
||||
typedef detail::thread::scoped_timed_read_write_lock<
|
||||
timed_read_write_mutex> scoped_timed_read_write_lock;
|
||||
|
||||
typedef detail::thread::scoped_read_lock<
|
||||
timed_read_write_mutex> scoped_read_lock;
|
||||
typedef detail::thread::scoped_try_read_lock<
|
||||
timed_read_write_mutex> scoped_try_read_lock;
|
||||
typedef detail::thread::scoped_timed_read_lock<
|
||||
timed_read_write_mutex> scoped_timed_read_lock;
|
||||
|
||||
typedef detail::thread::scoped_write_lock<
|
||||
timed_read_write_mutex> scoped_write_lock;
|
||||
typedef detail::thread::scoped_try_write_lock<
|
||||
timed_read_write_mutex> scoped_try_write_lock;
|
||||
typedef detail::thread::scoped_timed_write_lock<
|
||||
timed_read_write_mutex> scoped_timed_write_lock;
|
||||
|
||||
private:
|
||||
|
||||
// Operations that will eventually be done only
|
||||
// via lock types
|
||||
void do_write_lock();
|
||||
void do_read_lock();
|
||||
void do_write_unlock();
|
||||
void do_read_unlock();
|
||||
bool do_try_write_lock();
|
||||
bool do_try_read_lock();
|
||||
bool do_timed_write_lock(const xtime &xt);
|
||||
bool do_timed_read_lock(const xtime &xt);
|
||||
|
||||
void do_demote_to_read_lock();
|
||||
bool do_try_demote_to_read_lock();
|
||||
bool do_timed_demote_to_read_lock(const xtime &xt);
|
||||
|
||||
void do_promote_to_write_lock();
|
||||
bool do_try_promote_to_write_lock();
|
||||
bool do_timed_promote_to_write_lock(const xtime &xt);
|
||||
|
||||
bool locked();
|
||||
read_write_lock_state::read_write_lock_state_enum state();
|
||||
|
||||
detail::thread::read_write_mutex_impl<timed_mutex> m_impl;
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
// Change Log:
|
||||
// 10 Mar 02
|
||||
// Original version.
|
||||
// 4 May 04 GlassfordM
|
||||
// Implement lock promotion and demotion.
|
||||
// Add locked() and state() member functions for debugging
|
||||
// (should these be made public?).
|
||||
// Rename to improve consistency and eliminate abbreviations:
|
||||
// Use "read" and "write" instead of "shared" and "exclusive".
|
||||
// Change "rd" to "read", "wr" to "write", "rw" to "read_write".
|
||||
// Add mutex_type typdef.
|
||||
@@ -1,184 +1,15 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#include BOOST_THREAD_PLATFORM(recursive_mutex.hpp)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// disable warnings about non dll import
|
||||
// see: http://www.boost.org/more/separate_compilation.html#dlls
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251 4231 4660 4275)
|
||||
#endif
|
||||
class BOOST_THREAD_DECL recursive_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
||||
|
||||
recursive_mutex();
|
||||
~recursive_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_try_mutex> scoped_try_lock;
|
||||
|
||||
recursive_try_mutex();
|
||||
~recursive_try_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<
|
||||
recursive_timed_mutex> scoped_timed_lock;
|
||||
|
||||
recursive_timed_mutex();
|
||||
~recursive_timed_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
unsigned m_count;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
15
include/boost/thread/shared_mutex.hpp
Normal file
15
include/boost/thread/shared_mutex.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// shared_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#include BOOST_THREAD_PLATFORM(shared_mutex.hpp)
|
||||
|
||||
#endif
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
# include <boost/thread/condition.hpp>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
40
include/boost/thread/thread_time.hpp
Normal file
40
include/boost/thread/thread_time.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef BOOST_THREAD_TIME_HPP
|
||||
#define BOOST_THREAD_TIME_HPP
|
||||
#include <boost/date_time/microsec_time_clock.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef boost::posix_time::ptime system_time;
|
||||
|
||||
inline system_time get_system_time()
|
||||
{
|
||||
return boost::date_time::microsec_clock<system_time>::universal_time();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline system_time get_system_time_sentinel()
|
||||
{
|
||||
return system_time(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
inline unsigned long get_milliseconds_until(system_time const& target_time)
|
||||
{
|
||||
if(target_time.is_pos_infinity())
|
||||
{
|
||||
return ~(unsigned long)0;
|
||||
}
|
||||
system_time const now=get_system_time();
|
||||
if(target_time<=now)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return static_cast<unsigned long>((target_time-now).total_milliseconds()+1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
~tss();
|
||||
void* get() const;
|
||||
void set(void* value);
|
||||
|
||||
120
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
120
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "thread_primitives.hpp"
|
||||
#include "basic_timed_mutex.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename underlying_mutex_type>
|
||||
struct basic_recursive_mutex_impl
|
||||
{
|
||||
long recursion_count;
|
||||
long locking_thread_id;
|
||||
underlying_mutex_type mutex;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
recursion_count=0;
|
||||
locking_thread_id=0;
|
||||
mutex.initialize();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
mutex.destroy();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
if(!try_recursive_lock(current_thread_id))
|
||||
{
|
||||
mutex.lock();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
}
|
||||
}
|
||||
bool timed_lock(::boost::system_time const& target)
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
|
||||
}
|
||||
long get_active_count()
|
||||
{
|
||||
return mutex.get_active_count();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
if(!--recursion_count)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return mutex.locked();
|
||||
}
|
||||
|
||||
private:
|
||||
bool try_recursive_lock(long current_thread_id)
|
||||
{
|
||||
if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id)
|
||||
{
|
||||
++recursion_count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_basic_lock(long current_thread_id)
|
||||
{
|
||||
if(mutex.try_lock())
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_timed_lock(long current_thread_id,::boost::system_time const& target)
|
||||
{
|
||||
if(mutex.timed_lock(target))
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_timed_mutex;
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0}
|
||||
|
||||
#endif
|
||||
158
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
158
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_timed_mutex_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2006 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "interlocked_read.hpp"
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct basic_timed_mutex
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(long,lock_flag_value=0x80000000);
|
||||
long active_count;
|
||||
void* event;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
active_count=0;
|
||||
event=0;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
|
||||
if(old_event)
|
||||
{
|
||||
win32::CloseHandle(old_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
long old_count=active_count&~lock_flag_value;
|
||||
do
|
||||
{
|
||||
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
|
||||
if(current_count==old_count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
old_count=current_count;
|
||||
}
|
||||
while(!(old_count&lock_flag_value));
|
||||
return false;
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
bool const success=timed_lock(::boost::detail::get_system_time_sentinel());
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
bool timed_lock(::boost::system_time const& wait_until)
|
||||
{
|
||||
long old_count=active_count;
|
||||
while(true)
|
||||
{
|
||||
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
|
||||
if(current_count==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current_count;
|
||||
}
|
||||
|
||||
if(old_count&lock_flag_value)
|
||||
{
|
||||
bool lock_acquired=false;
|
||||
void* const sem=get_event();
|
||||
++old_count; // we're waiting, too
|
||||
do
|
||||
{
|
||||
old_count-=(lock_flag_value+1); // there will be one less active thread on this mutex when it gets unlocked
|
||||
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
}
|
||||
do
|
||||
{
|
||||
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,old_count|lock_flag_value,old_count);
|
||||
if(current_count==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current_count;
|
||||
}
|
||||
while(!(old_count&lock_flag_value));
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
while(!lock_acquired);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
long get_active_count()
|
||||
{
|
||||
return ::boost::detail::interlocked_read_acquire(&active_count);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
long const offset=lock_flag_value+1;
|
||||
long old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,(~offset)+1);
|
||||
|
||||
if(old_count>offset)
|
||||
{
|
||||
win32::SetEvent(get_event());
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return get_active_count()>=lock_flag_value;
|
||||
}
|
||||
|
||||
private:
|
||||
void* get_event()
|
||||
{
|
||||
void* current_event=::boost::detail::interlocked_read_acquire(&event);
|
||||
|
||||
if(!current_event)
|
||||
{
|
||||
void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
|
||||
void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
|
||||
if(old_event!=0)
|
||||
{
|
||||
win32::CloseHandle(new_event);
|
||||
return old_event;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new_event;
|
||||
}
|
||||
}
|
||||
return current_event;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
|
||||
|
||||
#endif
|
||||
309
include/boost/thread/win32/condition_variable.hpp
Normal file
309
include/boost/thread/win32/condition_variable.hpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <limits.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include "interlocked_read.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class basic_condition_variable
|
||||
{
|
||||
boost::mutex internal_mutex;
|
||||
long total_count;
|
||||
unsigned active_generation_count;
|
||||
|
||||
struct list_entry
|
||||
{
|
||||
detail::win32::handle semaphore;
|
||||
long count;
|
||||
bool notified;
|
||||
};
|
||||
|
||||
BOOST_STATIC_CONSTANT(unsigned,generation_count=3);
|
||||
|
||||
list_entry generations[generation_count];
|
||||
detail::win32::handle wake_sem;
|
||||
|
||||
static bool no_waiters(list_entry const& entry)
|
||||
{
|
||||
return entry.count==0;
|
||||
}
|
||||
|
||||
void shift_generations_down()
|
||||
{
|
||||
list_entry* const last_active_entry=std::remove_if(generations,generations+generation_count,no_waiters);
|
||||
if(last_active_entry==generations+generation_count)
|
||||
{
|
||||
broadcast_entry(generations[generation_count-1],false);
|
||||
}
|
||||
else
|
||||
{
|
||||
active_generation_count=(last_active_entry-generations)+1;
|
||||
}
|
||||
|
||||
std::copy_backward(generations,generations+active_generation_count-1,generations+active_generation_count);
|
||||
generations[0]=list_entry();
|
||||
}
|
||||
|
||||
void broadcast_entry(list_entry& entry,bool wake)
|
||||
{
|
||||
long const count_to_wake=entry.count;
|
||||
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
|
||||
if(wake)
|
||||
{
|
||||
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
|
||||
}
|
||||
detail::win32::ReleaseSemaphore(entry.semaphore,count_to_wake,0);
|
||||
entry.count=0;
|
||||
dispose_entry(entry);
|
||||
}
|
||||
|
||||
|
||||
void dispose_entry(list_entry& entry)
|
||||
{
|
||||
if(entry.semaphore)
|
||||
{
|
||||
unsigned long const close_result=detail::win32::CloseHandle(entry.semaphore);
|
||||
BOOST_ASSERT(close_result);
|
||||
entry.semaphore=0;
|
||||
}
|
||||
entry.notified=false;
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
struct relocker
|
||||
{
|
||||
lock_type& lock;
|
||||
bool unlocked;
|
||||
|
||||
relocker(lock_type& lock_):
|
||||
lock(lock_),unlocked(false)
|
||||
{}
|
||||
void unlock()
|
||||
{
|
||||
lock.unlock();
|
||||
unlocked=true;
|
||||
}
|
||||
~relocker()
|
||||
{
|
||||
if(unlocked)
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
template<typename lock_type>
|
||||
bool do_wait(lock_type& lock,::boost::system_time const& wait_until)
|
||||
{
|
||||
detail::win32::handle_manager local_wake_sem;
|
||||
detail::win32::handle_manager sem;
|
||||
bool first_loop=true;
|
||||
bool woken=false;
|
||||
|
||||
relocker<lock_type> locker(lock);
|
||||
|
||||
while(!woken)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
detail::interlocked_write_release(&total_count,total_count+1);
|
||||
if(first_loop)
|
||||
{
|
||||
locker.unlock();
|
||||
if(!wake_sem)
|
||||
{
|
||||
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
BOOST_ASSERT(wake_sem);
|
||||
}
|
||||
local_wake_sem=detail::win32::duplicate_handle(wake_sem);
|
||||
|
||||
if(generations[0].notified)
|
||||
{
|
||||
shift_generations_down();
|
||||
}
|
||||
else if(!active_generation_count)
|
||||
{
|
||||
active_generation_count=1;
|
||||
}
|
||||
|
||||
first_loop=false;
|
||||
}
|
||||
if(!generations[0].semaphore)
|
||||
{
|
||||
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
BOOST_ASSERT(generations[0].semaphore);
|
||||
}
|
||||
++generations[0].count;
|
||||
sem=detail::win32::duplicate_handle(generations[0].semaphore);
|
||||
}
|
||||
unsigned long const wait_result=detail::win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until));
|
||||
|
||||
if(wait_result==detail::win32::timeout)
|
||||
{
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT(!wait_result);
|
||||
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
|
||||
BOOST_ASSERT(woken_result==detail::win32::timeout || woken_result==0);
|
||||
|
||||
woken=(woken_result==0);
|
||||
}
|
||||
return woken;
|
||||
}
|
||||
|
||||
basic_condition_variable(const basic_condition_variable& other);
|
||||
basic_condition_variable& operator=(const basic_condition_variable& other);
|
||||
public:
|
||||
basic_condition_variable():
|
||||
total_count(0),active_generation_count(0),wake_sem(0)
|
||||
{
|
||||
for(unsigned i=0;i<generation_count;++i)
|
||||
{
|
||||
generations[i]=list_entry();
|
||||
}
|
||||
}
|
||||
|
||||
~basic_condition_variable()
|
||||
{
|
||||
for(unsigned i=0;i<generation_count;++i)
|
||||
{
|
||||
dispose_entry(generations[i]);
|
||||
}
|
||||
detail::win32::CloseHandle(wake_sem);
|
||||
}
|
||||
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
detail::win32::ReleaseSemaphore(wake_sem,1,0);
|
||||
for(unsigned generation=active_generation_count;generation!=0;--generation)
|
||||
{
|
||||
list_entry& entry=generations[generation-1];
|
||||
if(entry.count)
|
||||
{
|
||||
detail::interlocked_write_release(&total_count,total_count-1);
|
||||
entry.notified=true;
|
||||
detail::win32::ReleaseSemaphore(entry.semaphore,1,0);
|
||||
if(!--entry.count)
|
||||
{
|
||||
dispose_entry(entry);
|
||||
if(generation==active_generation_count)
|
||||
{
|
||||
--active_generation_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
for(unsigned generation=active_generation_count;generation!=0;--generation)
|
||||
{
|
||||
list_entry& entry=generations[generation-1];
|
||||
if(entry.count)
|
||||
{
|
||||
broadcast_entry(entry,true);
|
||||
}
|
||||
}
|
||||
active_generation_count=0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class condition_variable:
|
||||
public detail::basic_condition_variable
|
||||
{
|
||||
public:
|
||||
void wait(unique_lock<mutex>& m)
|
||||
{
|
||||
do_wait(m,::boost::detail::get_system_time_sentinel());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
return do_wait(m,wait_until);
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class condition_variable_any:
|
||||
public detail::basic_condition_variable
|
||||
{
|
||||
public:
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
do_wait(m,::boost::detail::get_system_time_sentinel());
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
return do_wait(m,wait_until);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
77
include/boost/thread/win32/interlocked_read.hpp
Normal file
77
include/boost/thread/win32/interlocked_read.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
|
||||
// interlocked_read_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
||||
extern "C" void _ReadWriteBarrier(void);
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
long const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
void* const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0);
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
|
||||
}
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(x,value);
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
61
include/boost/thread/win32/mutex.hpp
Normal file
61
include/boost/thread/win32/mutex.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "basic_timed_mutex.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
typedef ::boost::detail::basic_timed_mutex underlying_mutex;
|
||||
}
|
||||
|
||||
class mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::underlying_mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_timed_mutex
|
||||
{
|
||||
public:
|
||||
timed_mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
~timed_mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
132
include/boost/thread/win32/once.hpp
Normal file
132
include/boost/thread/win32/once.hpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#ifndef BOOST_THREAD_WIN32_ONCE_HPP
|
||||
#define BOOST_THREAD_WIN32_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2005 John Maddock
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std
|
||||
{
|
||||
using ::memcpy;
|
||||
using ::ptrdiff_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef long once_flag;
|
||||
|
||||
#define BOOST_ONCE_INIT 0
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct win32_mutex_scoped_lock
|
||||
{
|
||||
void* const mutex_handle;
|
||||
explicit win32_mutex_scoped_lock(void* mutex_handle_):
|
||||
mutex_handle(mutex_handle_)
|
||||
{
|
||||
unsigned long const res=win32::WaitForSingleObject(mutex_handle,win32::infinite);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
~win32_mutex_scoped_lock()
|
||||
{
|
||||
bool const success=win32::ReleaseMutex(mutex_handle)!=0;
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
template <class I>
|
||||
void int_to_string(I p, wchar_t* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
*buf = L'A' + static_cast<wchar_t>((p >> (i*4)) & 0x0f);
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
#else
|
||||
template <class I>
|
||||
void int_to_string(I p, char* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
*buf = 'A' + static_cast<char>((p >> (i*4)) & 0x0f);
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// create a named mutex. It doesn't really matter what this name is
|
||||
// as long as it is unique both to this process, and to the address of "flag":
|
||||
inline void* create_once_mutex(void* flag_address)
|
||||
{
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
typedef wchar_t char_type;
|
||||
static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#else
|
||||
typedef char char_type;
|
||||
static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#endif
|
||||
unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type);
|
||||
unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1;
|
||||
unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2;
|
||||
char_type mutex_name[once_mutex_name_length];
|
||||
|
||||
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t));
|
||||
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length);
|
||||
detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
return win32::CreateMutexW(NULL, 0, mutex_name);
|
||||
#else
|
||||
return win32::CreateMutexA(NULL, 0, mutex_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
// Try for a quick win: if the procedure has already been called
|
||||
// just skip through:
|
||||
long const function_complete_flag_value=0xc15730e2;
|
||||
|
||||
if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
|
||||
{
|
||||
void* const mutex_handle(::boost::detail::create_once_mutex(&flag));
|
||||
BOOST_ASSERT(mutex_handle);
|
||||
detail::win32::handle_manager const closer(mutex_handle);
|
||||
detail::win32_mutex_scoped_lock const lock(mutex_handle);
|
||||
|
||||
if(flag!=function_complete_flag_value)
|
||||
{
|
||||
f();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
61
include/boost/thread/win32/recursive_mutex.hpp
Normal file
61
include/boost/thread/win32/recursive_mutex.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include "basic_recursive_mutex.hpp"
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_recursive_mutex
|
||||
{
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::initialize();
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_recursive_timed_mutex
|
||||
{
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::initialize();
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
516
include/boost/thread/win32/shared_mutex.hpp
Normal file
516
include/boost/thread/win32/shared_mutex.hpp
Normal file
@@ -0,0 +1,516 @@
|
||||
#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <limits.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex:
|
||||
private boost::noncopyable
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count:11;
|
||||
unsigned shared_waiting:11;
|
||||
unsigned exclusive:1;
|
||||
unsigned upgrade:1;
|
||||
unsigned exclusive_waiting:7;
|
||||
unsigned exclusive_waiting_blocked:1;
|
||||
|
||||
friend bool operator==(state_data const& lhs,state_data const& rhs)
|
||||
{
|
||||
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
T interlocked_compare_exchange(T* target,T new_value,T comparand)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
|
||||
long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
|
||||
*reinterpret_cast<long*>(&new_value),
|
||||
*reinterpret_cast<long*>(&comparand));
|
||||
return *reinterpret_cast<T const*>(&res);
|
||||
}
|
||||
|
||||
state_data state;
|
||||
void* semaphores[2];
|
||||
void* &unlock_sem;
|
||||
void* &exclusive_sem;
|
||||
void* upgrade_sem;
|
||||
|
||||
void release_waiters(state_data old_state)
|
||||
{
|
||||
if(old_state.exclusive_waiting)
|
||||
{
|
||||
bool const success=detail::win32::ReleaseSemaphore(exclusive_sem,1,NULL)!=0;
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
|
||||
if(old_state.shared_waiting || old_state.exclusive_waiting)
|
||||
{
|
||||
bool const success=detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),NULL)!=0;
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex():
|
||||
unlock_sem(semaphores[0]),
|
||||
exclusive_sem(semaphores[1])
|
||||
{
|
||||
unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
detail::win32::CloseHandle(upgrade_sem);
|
||||
detail::win32::CloseHandle(unlock_sem);
|
||||
detail::win32::CloseHandle(exclusive_sem);
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
bool const success=timed_lock_shared(::boost::detail::get_system_time_sentinel());
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
|
||||
bool timed_lock_shared(boost::system_time const& wait_until)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(new_state.shared_waiting)
|
||||
{
|
||||
--new_state.shared_waiting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.upgrade)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
if(old_state.upgrade)
|
||||
{
|
||||
bool const success=detail::win32::ReleaseSemaphore(upgrade_sem,1,NULL)!=0;
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
else
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
bool const success=timed_lock(::boost::detail::get_system_time_sentinel());
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
|
||||
bool timed_lock(boost::system_time const& wait_until)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
state_data old_state=state;
|
||||
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
++new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(wait_res<2);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
new_state.upgrade=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite);
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(!last_reader)
|
||||
{
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite);
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
new_state.upgrade=true;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
211
include/boost/thread/win32/thread_primitives.hpp
Normal file
211
include/boost/thread/win32/thread_primitives.hpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
#define BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
|
||||
// win32_thread_primitives.hpp
|
||||
//
|
||||
// (C) Copyright 2005-6 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
typedef ULONG_PTR ulong_ptr;
|
||||
typedef HANDLE handle;
|
||||
unsigned const infinite=INFINITE;
|
||||
unsigned const timeout=WAIT_TIMEOUT;
|
||||
|
||||
using ::CreateMutexA;
|
||||
using ::CreateEventA;
|
||||
using ::CreateSemaphoreA;
|
||||
using ::CloseHandle;
|
||||
using ::ReleaseMutex;
|
||||
using ::ReleaseSemaphore;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
using ::WaitForMultipleObjects;
|
||||
using ::WaitForSingleObject;
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::DuplicateHandle;
|
||||
using ::SleepEx;
|
||||
using ::QueueUserAPC;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
typedef unsigned long ulong_ptr;
|
||||
# endif
|
||||
typedef void* handle;
|
||||
unsigned const infinite=~0U;
|
||||
unsigned const timeout=258U;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
struct _SECURITY_ATTRIBUTES;
|
||||
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
|
||||
__declspec(dllimport) int __stdcall CloseHandle(void*);
|
||||
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
|
||||
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
|
||||
__declspec(dllimport) void* __stdcall GetCurrentThread();
|
||||
__declspec(dllimport) void* __stdcall GetCurrentProcess();
|
||||
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
|
||||
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
|
||||
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||
__declspec(dllimport) int __stdcall SetEvent(void*);
|
||||
__declspec(dllimport) int __stdcall ResetEvent(void*);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# error "Win32 functions not available"
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
enum event_type
|
||||
{
|
||||
auto_reset_event=false,
|
||||
manual_reset_event=true
|
||||
};
|
||||
|
||||
enum initial_event_state
|
||||
{
|
||||
event_initially_reset=false,
|
||||
event_initially_set=true
|
||||
};
|
||||
|
||||
inline handle create_anonymous_event(event_type type,initial_event_state state)
|
||||
{
|
||||
handle const res=win32::CreateEventA(0,type,state,0);
|
||||
if(!res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle create_anonymous_semaphore(long initial_count,long max_count)
|
||||
{
|
||||
handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL);
|
||||
if(!res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle duplicate_handle(handle source)
|
||||
{
|
||||
handle const current_process=GetCurrentProcess();
|
||||
long const same_access_flag=2;
|
||||
handle new_handle=0;
|
||||
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
|
||||
if(!success)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return new_handle;
|
||||
}
|
||||
|
||||
inline void release_semaphore(handle semaphore,long count)
|
||||
{
|
||||
bool const success=ReleaseSemaphore(semaphore,count,0)!=0;
|
||||
BOOST_ASSERT(success);
|
||||
}
|
||||
|
||||
class handle_manager
|
||||
{
|
||||
private:
|
||||
handle handle_to_manage;
|
||||
handle_manager(handle_manager&);
|
||||
handle_manager& operator=(handle_manager&);
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(handle_to_manage)
|
||||
{
|
||||
unsigned long result=CloseHandle(handle_to_manage);
|
||||
BOOST_ASSERT(result);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit handle_manager(handle handle_to_manage_):
|
||||
handle_to_manage(handle_to_manage_)
|
||||
{}
|
||||
handle_manager():
|
||||
handle_to_manage(0)
|
||||
{}
|
||||
|
||||
handle_manager& operator=(handle new_handle)
|
||||
{
|
||||
cleanup();
|
||||
handle_to_manage=new_handle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator handle() const
|
||||
{
|
||||
return handle_to_manage;
|
||||
}
|
||||
|
||||
handle release()
|
||||
{
|
||||
handle const res=handle_to_manage;
|
||||
handle_to_manage=0;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
return !handle_to_manage;
|
||||
}
|
||||
|
||||
~handle_manager()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,6 +11,8 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -37,6 +40,18 @@ struct xtime
|
||||
|
||||
xtime_sec_t sec;
|
||||
xtime_nsec_t nsec;
|
||||
|
||||
operator system_time() const
|
||||
{
|
||||
return boost::posix_time::from_time_t(0)+
|
||||
boost::posix_time::seconds(static_cast<long>(sec))+
|
||||
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
|
||||
boost::posix_time::nanoseconds(nsec);
|
||||
#else
|
||||
boost::posix_time::microseconds((nsec+500)/1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
|
||||
@@ -49,6 +64,16 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||
return (xt1.sec > xt2.sec) ? 1 : -1;
|
||||
}
|
||||
|
||||
inline xtime get_xtime(boost::system_time const& abs_time)
|
||||
{
|
||||
xtime res={0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
res.sec=static_cast<xtime::xtime_sec_t>(time_since_epoch.total_seconds());
|
||||
res.nsec=static_cast<xtime::xtime_nsec_t>(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()));
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif //BOOST_XTIME_WEK070601_HPP
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/barrier.hpp>
|
||||
#include <string> // see http://article.gmane.org/gmane.comp.lib.boost.devel/106981
|
||||
|
||||
namespace boost {
|
||||
|
||||
barrier::barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::invalid_argument("count cannot be zero.");
|
||||
}
|
||||
|
||||
barrier::~barrier()
|
||||
{
|
||||
}
|
||||
|
||||
bool barrier::wait()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
{
|
||||
m_generation++;
|
||||
m_count = m_threshold;
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,672 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <cassert>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
||||
m_queue = reinterpret_cast<void*>(
|
||||
CreateSemaphore(0, 0, (std::numeric_limits<long>::max)(), 0));
|
||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||
|
||||
if (!m_gate || !m_queue || !m_mutex)
|
||||
{
|
||||
int res = 0;
|
||||
if (m_gate)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
}
|
||||
if (m_mutex)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
signals = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
++m_blocked;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_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<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
bool ret = false;
|
||||
unsigned int res = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
ret = (res == WAIT_OBJECT_0);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_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<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_broadcast(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait(pthread_mutex_t* pmutex)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_wait(&m_condition, pmutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||
{
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
|
||||
int res = 0;
|
||||
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
|
||||
assert(res == 0 || res == ETIMEDOUT);
|
||||
|
||||
return res != ETIMEDOUT;
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
using threads::mac::detail::safe_wait_on_semaphore;
|
||||
|
||||
condition_impl::condition_impl()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
threads::mac::detail::thread_init();
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
|
||||
lStatus = MPCreateSemaphore(1, 1, &m_gate);
|
||||
if(lStatus == noErr)
|
||||
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
|
||||
|
||||
if(lStatus != noErr || !m_gate || !m_queue)
|
||||
{
|
||||
if (m_gate)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
++m_blocked;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_queue, milliseconds);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
|
||||
bool ret = (lStatus == noErr);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
561
src/mutex.cpp
561
src/mutex.cpp
@@ -1,561 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# include <new>
|
||||
# include <boost/thread/once.hpp>
|
||||
# include <windows.h>
|
||||
# include <time.h>
|
||||
# include "mutex.inl"
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = true;
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = has_TryEnterCriticalSection();
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
return wait_critical_section_try(m_mutex);
|
||||
else
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_mutex(0)
|
||||
{
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
int res = wait_mutex(m_mutex, milliseconds);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
boost::xtime cur;
|
||||
boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
if (boost::xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
return res == WAIT_OBJECT_0;
|
||||
}
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_trylock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0 || res == EBUSY);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_locked(false)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
assert(!m_locked);
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts);
|
||||
assert(res == 0 || res == ETIMEDOUT);
|
||||
|
||||
if (res == ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
int res = 0;
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return lStatus == noErr;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int microseconds;
|
||||
to_microduration(xt, microseconds);
|
||||
Duration lDuration = kDurationMicrosecond * microseconds;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
122
src/mutex.inl
122
src/mutex.inl
@@ -1,122 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
//:PREVENT THIS FROM BEING DUPLICATED
|
||||
typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection);
|
||||
TryEnterCriticalSection_type g_TryEnterCriticalSection = 0;
|
||||
boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT;
|
||||
|
||||
void init_TryEnterCriticalSection()
|
||||
{
|
||||
//TryEnterCriticalSection is only available on WinNT 4.0 or later;
|
||||
//it is not available on Win9x.
|
||||
|
||||
OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)};
|
||||
::GetVersionEx(&version_info);
|
||||
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
||||
version_info.dwMajorVersion >= 4)
|
||||
{
|
||||
if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL")))
|
||||
g_TryEnterCriticalSection = reinterpret_cast<TryEnterCriticalSection_type>(GetProcAddress(kernel_module, TEXT("TryEnterCriticalSection")));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool has_TryEnterCriticalSection()
|
||||
{
|
||||
boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection);
|
||||
return g_TryEnterCriticalSection != 0;
|
||||
}
|
||||
|
||||
inline HANDLE mutex_cast(void* p)
|
||||
{
|
||||
return reinterpret_cast<HANDLE>(p);
|
||||
}
|
||||
|
||||
inline LPCRITICAL_SECTION critical_section_cast(void* p)
|
||||
{
|
||||
return reinterpret_cast<LPCRITICAL_SECTION>(p);
|
||||
}
|
||||
|
||||
inline void* new_critical_section()
|
||||
{
|
||||
try
|
||||
{
|
||||
LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION;
|
||||
if (critical_section == 0) throw boost::thread_resource_error();
|
||||
InitializeCriticalSection(critical_section);
|
||||
return critical_section;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
inline void* new_mutex(const char* name)
|
||||
{
|
||||
#if defined(BOOST_NO_ANSI_APIS)
|
||||
int num_wide_chars = (strlen(name) + 1);
|
||||
LPWSTR wide_name = (LPWSTR)_alloca( num_wide_chars * 2 );
|
||||
::MultiByteToWideChar(CP_ACP, 0, name, -1, wide_name, num_wide_chars);
|
||||
HANDLE mutex = CreateMutexW(0, 0, wide_name);
|
||||
#else
|
||||
HANDLE mutex = CreateMutexA(0, 0, name);
|
||||
#endif
|
||||
if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?)
|
||||
throw boost::thread_resource_error();
|
||||
return reinterpret_cast<void*>(mutex);
|
||||
}
|
||||
|
||||
inline void delete_critical_section(void* mutex)
|
||||
{
|
||||
DeleteCriticalSection(critical_section_cast(mutex));
|
||||
delete critical_section_cast(mutex);
|
||||
}
|
||||
|
||||
inline void delete_mutex(void* mutex)
|
||||
{
|
||||
int res = 0;
|
||||
res = CloseHandle(mutex_cast(mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
inline void wait_critical_section_infinite(void* mutex)
|
||||
{
|
||||
EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions
|
||||
}
|
||||
|
||||
inline bool wait_critical_section_try(void* mutex)
|
||||
{
|
||||
BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex));
|
||||
return res != 0;
|
||||
}
|
||||
|
||||
inline int wait_mutex(void* mutex, int time)
|
||||
{
|
||||
unsigned int res = 0;
|
||||
res = WaitForSingleObject(mutex_cast(mutex), time);
|
||||
//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void release_critical_section(void* mutex)
|
||||
{
|
||||
LeaveCriticalSection(critical_section_cast(mutex));
|
||||
}
|
||||
|
||||
inline void release_mutex(void* mutex)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
res = ReleaseMutex(mutex_cast(mutex));
|
||||
assert(res);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
207
src/once.cpp
207
src/once.cpp
@@ -1,207 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
|
||||
using std::size_t;
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include "mutex.inl"
|
||||
# if defined(BOOST_NO_STRINGSTREAM)
|
||||
# include <strstream>
|
||||
|
||||
class unfreezer
|
||||
{
|
||||
public:
|
||||
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||
~unfreezer() { m_stream.freeze(false); }
|
||||
private:
|
||||
std::ostrstream& m_stream;
|
||||
};
|
||||
|
||||
# else
|
||||
# include <sstream>
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::sprintf; }
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
namespace {
|
||||
pthread_key_t key;
|
||||
pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
|
||||
typedef void (*once_callback)();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void key_init()
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
|
||||
static void do_once()
|
||||
{
|
||||
once_callback* cb = reinterpret_cast<once_callback*>(
|
||||
pthread_getspecific(key));
|
||||
(**cb)();
|
||||
}
|
||||
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
namespace {
|
||||
void *remote_call_proxy(void *pData)
|
||||
{
|
||||
std::pair<void (*)(), boost::once_flag *> &rData(
|
||||
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||
|
||||
if(*rData.second == false)
|
||||
{
|
||||
rData.first();
|
||||
*rData.second = true;
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_WINTHREADS)
|
||||
namespace {
|
||||
// The signature for InterlockedCompareExchange has changed with the
|
||||
// addition of Win64 support. I can't determine any (consistent and
|
||||
// portable) way of using conditional compilation to detect this, so
|
||||
// we use these type wrappers. Unfortunately, the various vendors
|
||||
// use different calling conventions and other signature anamolies,
|
||||
// and thus have unique types as well. This is known to work on VC6,
|
||||
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
||||
// other platforms?
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(dest, exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
|
||||
}
|
||||
|
||||
// The friendly form of InterlockedCompareExchange that defers
|
||||
// according to the above function type wrappers.
|
||||
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
return InterlockedCompareExchange(dest, exch, cmp);
|
||||
#else
|
||||
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
void call_once(void (*func)(), once_flag& flag)
|
||||
{
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
#if defined(BOOST_NO_STRINGSTREAM)
|
||||
std::ostrstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag
|
||||
<< std::ends;
|
||||
unfreezer unfreeze(strm);
|
||||
HANDLE mutex=new_mutex(strm.str());
|
||||
#else
|
||||
# if defined (BOOST_NO_ANSI_APIS)
|
||||
std::wostringstream strm;
|
||||
strm << L"2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag;
|
||||
HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str());
|
||||
# else
|
||||
std::ostringstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag;
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
||||
# endif
|
||||
#endif
|
||||
assert(mutex != NULL);
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(mutex, INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
func();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
throw;
|
||||
}
|
||||
InterlockedExchange(&flag, 1);
|
||||
}
|
||||
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_once(&once, &key_init);
|
||||
pthread_setspecific(key, &func);
|
||||
pthread_once(&flag, do_once);
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
if(flag == false)
|
||||
{
|
||||
// all we do here is make a remote call to blue, as blue is not
|
||||
// reentrant.
|
||||
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||
assert(flag == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,6 +10,7 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <cassert>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
@@ -89,18 +91,6 @@ public:
|
||||
bool m_started;
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
struct on_thread_exit_guard
|
||||
{
|
||||
~on_thread_exit_guard()
|
||||
{
|
||||
on_thread_exit();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
extern "C" {
|
||||
@@ -112,25 +102,13 @@ extern "C" {
|
||||
static OSStatus thread_proxy(void* param)
|
||||
#endif
|
||||
{
|
||||
// try
|
||||
{
|
||||
thread_param* p = static_cast<thread_param*>(param);
|
||||
boost::function0<void> threadfunc = p->m_threadfunc;
|
||||
p->started();
|
||||
threadfunc();
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
on_thread_exit_guard guard;
|
||||
|
||||
on_thread_exit();
|
||||
#endif
|
||||
|
||||
thread_param* p = static_cast<thread_param*>(param);
|
||||
boost::function0<void> threadfunc = p->m_threadfunc;
|
||||
p->started();
|
||||
threadfunc();
|
||||
}
|
||||
// catch (...)
|
||||
// {
|
||||
//#if defined(BOOST_HAS_WINTHREADS)
|
||||
// on_thread_exit();
|
||||
//#endif
|
||||
// }
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
::boost::detail::thread_cleanup();
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
|
||||
14
src/tss.cpp
14
src/tss.cpp
@@ -31,7 +31,7 @@ boost::once_flag tss_data_once = BOOST_ONCE_INIT;
|
||||
boost::mutex* tss_data_mutex = 0;
|
||||
tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
DWORD tss_data_native_key;
|
||||
DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_key_t tss_data_native_key;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
@@ -60,6 +60,7 @@ void tss_data_dec_use(boost::mutex::scoped_lock& lk)
|
||||
tss_data_mutex = 0;
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
TlsFree(tss_data_native_key);
|
||||
tss_data_native_key=TLS_OUT_OF_INDEXES;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_key_delete(tss_data_native_key);
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
@@ -78,13 +79,17 @@ extern "C" void cleanup_slots(void* p)
|
||||
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
|
||||
(*slots)[i] = 0;
|
||||
}
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
TlsSetValue(tss_data_native_key,0);
|
||||
#endif
|
||||
tss_data_dec_use(lock);
|
||||
delete slots;
|
||||
}
|
||||
|
||||
void init_tss_data()
|
||||
{
|
||||
std::auto_ptr<tss_data_cleanup_handlers_type> temp(new tss_data_cleanup_handlers_type);
|
||||
std::auto_ptr<tss_data_cleanup_handlers_type>
|
||||
temp(new tss_data_cleanup_handlers_type);
|
||||
|
||||
std::auto_ptr<boost::mutex> temp_mutex(new boost::mutex);
|
||||
if (temp_mutex.get() == 0)
|
||||
@@ -96,9 +101,8 @@ void init_tss_data()
|
||||
|
||||
//Allocate tls slot
|
||||
tss_data_native_key = TlsAlloc();
|
||||
if (tss_data_native_key == 0xFFFFFFFF)
|
||||
if (tss_data_native_key == TLS_OUT_OF_INDEXES)
|
||||
return;
|
||||
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
|
||||
if (res != 0)
|
||||
@@ -178,7 +182,7 @@ namespace boost {
|
||||
namespace detail {
|
||||
void tss::init(boost::function1<void, void*>* pcleanup)
|
||||
{
|
||||
boost::call_once(&init_tss_data, tss_data_once);
|
||||
boost::call_once(tss_data_once, &init_tss_data);
|
||||
if (tss_data_cleanup_handlers == 0)
|
||||
throw thread_resource_error();
|
||||
boost::mutex::scoped_lock lock(*tss_data_mutex);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// Copyright (c) 2006 Peter Dimov
|
||||
// Copyright (c) 2006 Anthony Williams
|
||||
//
|
||||
// Copyright (C) 2004 Michael Glassford
|
||||
// Copyright (C) 2006 Roland Schwarz
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,152 +8,205 @@
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
// #include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <list>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
typedef std::list<thread_exit_handler> thread_exit_handlers;
|
||||
|
||||
const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
|
||||
DWORD tls_key = invalid_tls_key;
|
||||
|
||||
boost::once_flag once_init_tls_key = BOOST_ONCE_INIT;
|
||||
|
||||
void init_tls_key()
|
||||
{
|
||||
tls_key = TlsAlloc();
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
extern "C" BOOST_THREAD_DECL int at_thread_exit( thread_exit_handler exit_handler )
|
||||
{
|
||||
boost::call_once( init_tls_key, once_init_tls_key );
|
||||
|
||||
if( tls_key == invalid_tls_key )
|
||||
namespace
|
||||
{
|
||||
return -1;
|
||||
class CScopedCSLock
|
||||
{
|
||||
public:
|
||||
CScopedCSLock(LPCRITICAL_SECTION cs) : cs(cs), lk(true) {
|
||||
::EnterCriticalSection(cs);
|
||||
}
|
||||
~CScopedCSLock() {
|
||||
if (lk) ::LeaveCriticalSection(cs);
|
||||
}
|
||||
void Unlock() {
|
||||
lk = false;
|
||||
::LeaveCriticalSection(cs);
|
||||
}
|
||||
private:
|
||||
bool lk;
|
||||
LPCRITICAL_SECTION cs;
|
||||
};
|
||||
|
||||
typedef std::list<thread_exit_handler> thread_exit_handlers;
|
||||
|
||||
boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT;
|
||||
//boost::mutex* threadmon_mutex;
|
||||
// We don't use boost::mutex here, to avoid a memory leak report,
|
||||
// because we cannot delete it again easily.
|
||||
CRITICAL_SECTION threadmon_mutex;
|
||||
void init_threadmon_mutex(void)
|
||||
{
|
||||
//threadmon_mutex = new boost::mutex;
|
||||
//if (!threadmon_mutex)
|
||||
// throw boost::thread_resource_error();
|
||||
::InitializeCriticalSection(&threadmon_mutex);
|
||||
}
|
||||
|
||||
const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
|
||||
DWORD tls_key = invalid_tls_key;
|
||||
|
||||
unsigned long attached_thread_count = 0;
|
||||
}
|
||||
|
||||
// Get the exit handlers list for the current thread from tls.
|
||||
/*
|
||||
Calls to DllMain() and tls_callback() are serialized by the OS;
|
||||
however, calls to at_thread_exit are not, so it must be protected
|
||||
by a mutex. Since we already need a mutex for at_thread_exit(),
|
||||
and since there is no guarantee that on_process_enter(),
|
||||
on_process_exit(), on_thread_enter(), and on_thread_exit()
|
||||
will be called only from DllMain() or tls_callback(), it makes
|
||||
sense to protect those, too.
|
||||
*/
|
||||
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast< thread_exit_handlers* >( TlsGetValue( tls_key ) );
|
||||
|
||||
if( exit_handlers == 0 )
|
||||
extern "C" BOOST_THREAD_DECL int at_thread_exit(
|
||||
thread_exit_handler exit_handler
|
||||
)
|
||||
{
|
||||
// No exit handlers list was created yet.
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
//boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
//Allocate a tls slot if necessary.
|
||||
|
||||
if (tls_key == invalid_tls_key)
|
||||
tls_key = TlsAlloc();
|
||||
|
||||
if (tls_key == invalid_tls_key)
|
||||
return -1;
|
||||
|
||||
//Get the exit handlers list for the current thread from tls.
|
||||
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
|
||||
|
||||
if (!exit_handlers)
|
||||
{
|
||||
//No exit handlers list was created yet.
|
||||
|
||||
try
|
||||
{
|
||||
//Attempt to create a new exit handlers list.
|
||||
|
||||
exit_handlers = new thread_exit_handlers;
|
||||
if (!exit_handlers)
|
||||
return -1;
|
||||
|
||||
//Attempt to store the list pointer in tls.
|
||||
|
||||
if (TlsSetValue(tls_key, exit_handlers))
|
||||
++attached_thread_count;
|
||||
else
|
||||
{
|
||||
delete exit_handlers;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Like the C runtime library atexit() function,
|
||||
//functions should be called in the reverse of
|
||||
//the order they are added, so push them on the
|
||||
//front of the list.
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to create a new exit handlers list.
|
||||
|
||||
exit_handlers = new thread_exit_handlers;
|
||||
|
||||
if( exit_handlers == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Attempt to store the list pointer in tls.
|
||||
|
||||
if( !TlsSetValue( tls_key, exit_handlers ) )
|
||||
{
|
||||
delete exit_handlers;
|
||||
return -1;
|
||||
}
|
||||
exit_handlers->push_front(exit_handler);
|
||||
}
|
||||
catch( ... )
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Like the atexit() function, a result of zero
|
||||
//indicates success.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Like the C runtime library atexit() function,
|
||||
// functions should be called in the reverse of
|
||||
// the order they are added, so push them on the
|
||||
// front of the list.
|
||||
extern "C" BOOST_THREAD_DECL void on_process_enter(void)
|
||||
{
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
// boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
try
|
||||
{
|
||||
exit_handlers->push_front( exit_handler );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return -1;
|
||||
BOOST_ASSERT(attached_thread_count == 0);
|
||||
}
|
||||
|
||||
// Like the atexit() function, a result of zero
|
||||
// indicates success.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_enter()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit()
|
||||
{
|
||||
if( tls_key != invalid_tls_key )
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
|
||||
{
|
||||
TlsFree(tls_key);
|
||||
}
|
||||
}
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
// boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_enter()
|
||||
{
|
||||
}
|
||||
BOOST_ASSERT(attached_thread_count == 0);
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit()
|
||||
{
|
||||
// Initializing tls_key here ensures its proper visibility
|
||||
boost::call_once( init_tls_key, once_init_tls_key );
|
||||
//Free the tls slot if one was allocated.
|
||||
|
||||
// Get the exit handlers list for the current thread from tls.
|
||||
|
||||
if( tls_key == invalid_tls_key )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast< thread_exit_handlers* >( TlsGetValue( tls_key ) );
|
||||
|
||||
// If a handlers list was found, invoke its handlers.
|
||||
|
||||
if( exit_handlers != 0 )
|
||||
{
|
||||
// Call each handler and remove it from the list
|
||||
|
||||
while( !exit_handlers->empty() )
|
||||
if (tls_key != invalid_tls_key)
|
||||
{
|
||||
if( thread_exit_handler exit_handler = *exit_handlers->begin() )
|
||||
TlsFree(tls_key);
|
||||
tls_key = invalid_tls_key;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_enter(void)
|
||||
{
|
||||
//boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
|
||||
//boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
|
||||
{
|
||||
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
|
||||
// boost::mutex::scoped_lock lock(*threadmon_mutex);
|
||||
CScopedCSLock lock(&threadmon_mutex);
|
||||
|
||||
//Get the exit handlers list for the current thread from tls.
|
||||
|
||||
if (tls_key == invalid_tls_key)
|
||||
return;
|
||||
|
||||
thread_exit_handlers* exit_handlers =
|
||||
static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
|
||||
|
||||
//If a handlers list was found, use it.
|
||||
|
||||
if (exit_handlers && TlsSetValue(tls_key, 0))
|
||||
{
|
||||
BOOST_ASSERT(attached_thread_count > 0);
|
||||
--attached_thread_count;
|
||||
|
||||
//lock.unlock();
|
||||
lock.Unlock();
|
||||
|
||||
//Call each handler and remove it from the list
|
||||
|
||||
while (!exit_handlers->empty())
|
||||
{
|
||||
(*exit_handler)();
|
||||
if (thread_exit_handler exit_handler = *exit_handlers->begin())
|
||||
(*exit_handler)();
|
||||
exit_handlers->pop_front();
|
||||
}
|
||||
|
||||
exit_handlers->pop_front();
|
||||
}
|
||||
|
||||
// If TlsSetValue fails, we can't delete the list,
|
||||
// since a second call to on_thread_exit will try
|
||||
// to access it.
|
||||
|
||||
if( TlsSetValue( tls_key, 0 ) )
|
||||
{
|
||||
delete exit_handlers;
|
||||
exit_handlers = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
@@ -40,6 +40,7 @@ rule thread-run ( sources )
|
||||
[ thread-run test_once.cpp ]
|
||||
[ thread-run test_xtime.cpp ]
|
||||
[ thread-run test_barrier.cpp ]
|
||||
[ thread-run test_read_write_mutex.cpp ]
|
||||
[ thread-run test_shared_mutex.cpp ]
|
||||
[ thread-run test_lock_concept.cpp ]
|
||||
;
|
||||
}
|
||||
|
||||
173
test/test_lock_concept.cpp
Normal file
173
test/test_lock_concept.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/test_case_template.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_locked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_unlocked_with_defer_lock_parameter
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m,boost::defer_lock);
|
||||
|
||||
BOOST_CHECK(!lock);
|
||||
BOOST_CHECK(!lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_initially_locked_with_adopt_lock_parameter
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
m.lock();
|
||||
Lock lock(m,boost::adopt_lock);
|
||||
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_unlocked_after_unlock_called
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
BOOST_CHECK(!lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_locked_after_lock_called
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m,boost::defer_lock);
|
||||
lock.lock();
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_locked_after_try_lock_called
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m,boost::defer_lock);
|
||||
lock.try_lock();
|
||||
BOOST_CHECK(lock);
|
||||
BOOST_CHECK(lock.owns_lock());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_throws_if_lock_called_when_already_locked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
|
||||
BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_throws_if_try_lock_called_when_already_locked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
|
||||
BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex,typename Lock>
|
||||
struct test_throws_if_unlock_called_when_already_unlocked
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
Mutex m;
|
||||
Lock lock(m);
|
||||
lock.unlock();
|
||||
|
||||
BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
|
||||
{
|
||||
typedef typename Mutex::scoped_lock Lock;
|
||||
|
||||
test_initially_locked<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
|
||||
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
|
||||
test_unlocked_after_unlock_called<Mutex,Lock>()();
|
||||
test_locked_after_lock_called<Mutex,Lock>()();
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
}
|
||||
|
||||
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
|
||||
{
|
||||
typedef typename Mutex::scoped_try_lock Lock;
|
||||
|
||||
test_initially_locked<Mutex,Lock>()();
|
||||
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
|
||||
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
|
||||
test_unlocked_after_unlock_called<Mutex,Lock>()();
|
||||
test_locked_after_lock_called<Mutex,Lock>()();
|
||||
test_locked_after_try_lock_called<Mutex,Lock>()();
|
||||
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
|
||||
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
|
||||
|
||||
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types));
|
||||
|
||||
typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
|
||||
boost::recursive_try_mutex,boost::recursive_timed_mutex> try_mutex_types;
|
||||
|
||||
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,try_mutex_types));
|
||||
|
||||
return test;
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@@ -29,7 +29,7 @@ struct test_lock
|
||||
|
||||
// Test the lock's constructors.
|
||||
{
|
||||
lock_type lock(mutex, false);
|
||||
lock_type lock(mutex, boost::defer_lock);
|
||||
BOOST_CHECK(!lock);
|
||||
}
|
||||
lock_type lock(mutex);
|
||||
@@ -69,10 +69,10 @@ struct test_trylock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
}
|
||||
{
|
||||
try_lock_type lock(mutex, false);
|
||||
try_lock_type lock(mutex, boost::defer_lock);
|
||||
BOOST_CHECK(!lock);
|
||||
}
|
||||
try_lock_type lock(mutex, true);
|
||||
try_lock_type lock(mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
@@ -110,16 +110,16 @@ struct test_timedlock
|
||||
// Test the lock's constructors.
|
||||
{
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
boost::xtime xt = delay(0, 100);
|
||||
boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100);
|
||||
|
||||
timed_lock_type lock(mutex, xt);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
}
|
||||
{
|
||||
timed_lock_type lock(mutex, false);
|
||||
timed_lock_type lock(mutex, boost::defer_lock);
|
||||
BOOST_CHECK(!lock);
|
||||
}
|
||||
timed_lock_type lock(mutex, true);
|
||||
timed_lock_type lock(mutex);
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
|
||||
// Construct and initialize an xtime for a fast time out.
|
||||
@@ -139,8 +139,8 @@ struct test_timedlock
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
lock.unlock();
|
||||
BOOST_CHECK(!lock);
|
||||
xt = delay(0, 100);
|
||||
BOOST_CHECK(lock.timed_lock(xt));
|
||||
boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
|
||||
BOOST_CHECK(lock.timed_lock(target));
|
||||
BOOST_CHECK(lock ? true : false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,52 +1,160 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
#include <libs/thread/test/util.inl>
|
||||
boost::once_flag flag=BOOST_ONCE_INIT;
|
||||
int var_to_init=0;
|
||||
boost::mutex m;
|
||||
|
||||
int once_value = 0;
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
void init_once_value()
|
||||
void initialize_variable()
|
||||
{
|
||||
once_value++;
|
||||
// ensure that if multiple threads get in here, they are serialized, so we can see the effect
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++var_to_init;
|
||||
}
|
||||
|
||||
void test_once_thread()
|
||||
void call_once_thread()
|
||||
{
|
||||
boost::call_once(init_once_value, once);
|
||||
unsigned const loop_count=100;
|
||||
int my_once_value=0;
|
||||
for(unsigned i=0;i<loop_count;++i)
|
||||
{
|
||||
boost::call_once(flag, initialize_variable);
|
||||
my_once_value=var_to_init;
|
||||
if(my_once_value!=1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
BOOST_CHECK_EQUAL(my_once_value, 1);
|
||||
}
|
||||
|
||||
void do_test_once()
|
||||
void test_call_once()
|
||||
{
|
||||
const int NUMTHREADS=5;
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<NUMTHREADS; ++i)
|
||||
threads.create_thread(&test_once_thread);
|
||||
threads.join_all();
|
||||
BOOST_CHECK_EQUAL(once_value, 1);
|
||||
unsigned const num_threads=100;
|
||||
boost::thread_group group;
|
||||
|
||||
for(unsigned i=0;i<num_threads;++i)
|
||||
{
|
||||
group.create_thread(&call_once_thread);
|
||||
}
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(var_to_init,1);
|
||||
}
|
||||
|
||||
void test_once()
|
||||
int var_to_init_with_functor=0;
|
||||
|
||||
struct increment_value
|
||||
{
|
||||
timed_test(&do_test_once, 2);
|
||||
int* value;
|
||||
explicit increment_value(int* value_):
|
||||
value(value_)
|
||||
{}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++(*value);
|
||||
}
|
||||
};
|
||||
|
||||
void call_once_with_functor()
|
||||
{
|
||||
unsigned const loop_count=100;
|
||||
int my_once_value=0;
|
||||
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
|
||||
for(unsigned i=0;i<loop_count;++i)
|
||||
{
|
||||
boost::call_once(functor_flag, increment_value(&var_to_init_with_functor));
|
||||
my_once_value=var_to_init_with_functor;
|
||||
if(my_once_value!=1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
BOOST_CHECK_EQUAL(my_once_value, 1);
|
||||
}
|
||||
|
||||
void test_call_once_arbitrary_functor()
|
||||
{
|
||||
unsigned const num_threads=100;
|
||||
boost::thread_group group;
|
||||
|
||||
for(unsigned i=0;i<num_threads;++i)
|
||||
{
|
||||
group.create_thread(&call_once_with_functor);
|
||||
}
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
|
||||
}
|
||||
|
||||
|
||||
struct throw_before_third_pass
|
||||
{
|
||||
struct my_exception
|
||||
{};
|
||||
|
||||
static unsigned pass_counter;
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++pass_counter;
|
||||
if(pass_counter<3)
|
||||
{
|
||||
throw my_exception();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
unsigned throw_before_third_pass::pass_counter=0;
|
||||
unsigned exception_counter=0;
|
||||
|
||||
void call_once_with_exception()
|
||||
{
|
||||
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
|
||||
try
|
||||
{
|
||||
boost::call_once(functor_flag, throw_before_third_pass());
|
||||
}
|
||||
catch(throw_before_third_pass::my_exception)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
++exception_counter;
|
||||
}
|
||||
}
|
||||
|
||||
void test_call_once_retried_on_exception()
|
||||
{
|
||||
unsigned const num_threads=100;
|
||||
boost::thread_group group;
|
||||
|
||||
for(unsigned i=0;i<num_threads;++i)
|
||||
{
|
||||
group.create_thread(&call_once_with_exception);
|
||||
}
|
||||
group.join_all();
|
||||
BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3);
|
||||
BOOST_CHECK_EQUAL(exception_counter,2);
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: once test suite");
|
||||
BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_once));
|
||||
test->add(BOOST_TEST_CASE(test_call_once));
|
||||
test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor));
|
||||
test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception));
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -1,786 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/read_write_mutex.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define TS_CHECK(pred) \
|
||||
do { if (!(pred)) BOOST_ERROR (#pred); } while (0)
|
||||
#define TS_CHECK_MSG(pred, msg) \
|
||||
do { if (!(pred)) BOOST_ERROR (msg); } while (0)
|
||||
|
||||
namespace {
|
||||
|
||||
int shared_val = 0;
|
||||
|
||||
boost::xtime xsecs(int secs)
|
||||
{
|
||||
//Create an xtime that is secs seconds from now
|
||||
boost::xtime ret;
|
||||
TS_CHECK (boost::TIME_UTC == boost::xtime_get(&ret, boost::TIME_UTC));
|
||||
ret.sec += secs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MESSAGE "w1=" << w1.value_ << ", w2=" << w2.value_ << ", r1=" << r1.value_ << ", r2=" << r2.value_
|
||||
|
||||
template <typename RW>
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
|
||||
thread_adapter(
|
||||
void (*func)(void*, RW&),
|
||||
void* param1,
|
||||
RW ¶m2
|
||||
)
|
||||
: func_(func)
|
||||
, param1_(param1)
|
||||
, param2_(param2)
|
||||
{}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
func_(param1_, param2_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void (*func_)(void*, RW&);
|
||||
void* param1_;
|
||||
RW& param2_;
|
||||
};
|
||||
|
||||
const int k_data_init = -1;
|
||||
|
||||
template <typename RW>
|
||||
struct data
|
||||
{
|
||||
data(
|
||||
int id,
|
||||
RW& m,
|
||||
int wait_for_lock_secs,
|
||||
int sleep_with_lock_secs,
|
||||
bool demote_after_write = false
|
||||
)
|
||||
: id_(id)
|
||||
, wait_for_lock_secs_(wait_for_lock_secs)
|
||||
, sleep_with_lock_secs_(sleep_with_lock_secs)
|
||||
, test_promotion_and_demotion_(demote_after_write)
|
||||
, value_(k_data_init)
|
||||
, rw_(m)
|
||||
{}
|
||||
|
||||
int id_;
|
||||
int wait_for_lock_secs_;
|
||||
int sleep_with_lock_secs_;
|
||||
bool test_promotion_and_demotion_;
|
||||
int value_;
|
||||
|
||||
RW& rw_;
|
||||
};
|
||||
|
||||
template<typename RW>
|
||||
void plain_writer(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*) arg;
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
typename RW::scoped_read_write_lock l(
|
||||
rw,
|
||||
pdata->test_promotion_and_demotion_
|
||||
? boost::read_write_lock_state::read_locked
|
||||
: boost::read_write_lock_state::write_locked
|
||||
);
|
||||
|
||||
bool succeeded = true;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
{
|
||||
try
|
||||
{
|
||||
l.promote();
|
||||
}
|
||||
catch(const boost::lock_error&)
|
||||
{
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
shared_val += 10;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
l.demote();
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "plain_writer() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void plain_reader(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
TS_CHECK(!pdata->test_promotion_and_demotion_);
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "plain_reader() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void try_writer(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*) arg;
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
bool succeeded = false;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
succeeded = l.try_read_lock() && l.try_promote();
|
||||
else
|
||||
succeeded = l.try_write_lock();
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
shared_val += 10;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
l.demote();
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "try_writer() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void try_reader(void*arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
TS_CHECK(!pdata->test_promotion_and_demotion_);
|
||||
TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
|
||||
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (l.try_read_lock())
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "try_reader() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void timed_writer(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
|
||||
typename RW::scoped_timed_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
bool succeeded = false;
|
||||
|
||||
boost::xtime xt = xsecs(pdata->wait_for_lock_secs_);
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
succeeded = l.timed_read_lock(xt) && l.timed_promote(xt);
|
||||
else
|
||||
succeeded = l.timed_write_lock(xt);
|
||||
|
||||
if (succeeded)
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
shared_val += 10;
|
||||
|
||||
if (pdata->test_promotion_and_demotion_)
|
||||
l.demote();
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "timed_writer() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void timed_reader(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
data<RW>* pdata = (data<RW>*)arg;
|
||||
TS_CHECK(!pdata->test_promotion_and_demotion_);
|
||||
|
||||
typename RW::scoped_timed_read_write_lock l(rw,boost::read_write_lock_state::unlocked);
|
||||
|
||||
boost::xtime xt = xsecs(pdata->wait_for_lock_secs_);
|
||||
if (l.timed_read_lock(xt))
|
||||
{
|
||||
if (pdata->sleep_with_lock_secs_ > 0)
|
||||
boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
|
||||
|
||||
pdata->value_ = shared_val;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "timed_reader() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void clear_data(data<RW>& data1, data<RW>& data2, data<RW>& data3, data<RW>& data4)
|
||||
{
|
||||
shared_val = 0;
|
||||
data1.value_ = k_data_init;
|
||||
data2.value_ = k_data_init;
|
||||
data3.value_ = k_data_init;
|
||||
data4.value_ = k_data_init;
|
||||
}
|
||||
|
||||
bool shared_test_writelocked = false;
|
||||
bool shared_test_readlocked = false;
|
||||
bool shared_test_unlocked = false;
|
||||
|
||||
template<typename RW>
|
||||
void run_try_tests(void* arg, RW& rw)
|
||||
{
|
||||
try
|
||||
{
|
||||
TS_CHECK(shared_test_writelocked || shared_test_readlocked || shared_test_unlocked);
|
||||
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
|
||||
|
||||
if (shared_test_writelocked)
|
||||
{
|
||||
//Verify that write lock blocks other write locks
|
||||
TS_CHECK(!l.try_write_lock());
|
||||
|
||||
//Verify that write lock blocks read locks
|
||||
TS_CHECK(!l.try_read_lock());
|
||||
}
|
||||
else if (shared_test_readlocked)
|
||||
{
|
||||
//Verify that read lock blocks write locks
|
||||
TS_CHECK(!l.try_write_lock());
|
||||
|
||||
//Verify that read lock does not block other read locks
|
||||
TS_CHECK(l.try_read_lock());
|
||||
|
||||
//Verify that read lock blocks promotion
|
||||
TS_CHECK(!l.try_promote());
|
||||
}
|
||||
else if (shared_test_unlocked)
|
||||
{
|
||||
//Verify that unlocked does not blocks write locks
|
||||
TS_CHECK(l.try_write_lock());
|
||||
|
||||
//Verify that unlocked does not block demotion
|
||||
TS_CHECK(l.try_demote());
|
||||
|
||||
l.unlock();
|
||||
|
||||
//Verify that unlocked does not block read locks
|
||||
TS_CHECK(l.try_read_lock());
|
||||
|
||||
//Verify that unlocked does not block promotion
|
||||
TS_CHECK(l.try_promote());
|
||||
|
||||
l.unlock();
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
TS_CHECK_MSG(false, "run_try_tests() exception!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void test_plain_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
|
||||
{
|
||||
//Verify that a write lock prevents both readers and writers from obtaining a lock
|
||||
{
|
||||
shared_val = 0;
|
||||
data<RW> r1(1, rw, 0, 0);
|
||||
data<RW> r2(2, rw, 0, 0);
|
||||
data<RW> w1(3, rw, 0, 0);
|
||||
data<RW> w2(4, rw, 0, 0);
|
||||
|
||||
//Write-lock the mutex and queue up other readers and writers
|
||||
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
|
||||
|
||||
boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
|
||||
boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
|
||||
boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
|
||||
boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
//At this point, neither queued readers nor queued writers should have obtained access
|
||||
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
|
||||
if (test_promotion_and_demotion)
|
||||
{
|
||||
l.demote();
|
||||
boost::thread::sleep(xsecs(1));
|
||||
//:boost::thread tr3(thread_adapter<RW>(plain_reader, &r3, rw));
|
||||
|
||||
if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Since writers have priority, demotion doesn't release any readers.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Since readers have priority, demotion releases all readers.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
|
||||
{
|
||||
//Expected result:
|
||||
//Since readers can be released many at a time, demotion releases all queued readers.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
//:TS_CHECK_MSG(r3.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
|
||||
{
|
||||
//Expected result:
|
||||
//Since readers can be released only one at a time, demotion releases one queued reader.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init || r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init || r2.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ != r2.value_, MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
l.unlock();
|
||||
|
||||
tr2.join();
|
||||
tr1.join();
|
||||
tw2.join();
|
||||
tw1.join();
|
||||
|
||||
if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) either w1 or w2 obtains and releases the lock
|
||||
//2) the other of w1 and w2 obtains and releases the lock
|
||||
//3) r1 and r2 obtain and release the lock "simultaneously"
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 20, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//The same, except that either w1 or w2 (but not both) may
|
||||
//fail to promote to a write lock,
|
||||
//and r1, r2, or both may "sneak in" ahead of w1 and/or w2
|
||||
//by obtaining a read lock before w1 or w2 can promote
|
||||
//their initial read lock to a write lock.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init || r1.value_ == 10 || r1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init || r2.value_ == 10 || r2.value_ == 20, MESSAGE);
|
||||
}
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) r1 and r2 obtain and release the lock "simultaneously"
|
||||
//2) either w1 or w2 obtains and releases the lock
|
||||
//3) the other of w1 and w2 obtains and releases the lock
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//The same, except that either w1 or w2 (but not both) may
|
||||
//fail to promote to a write lock.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) r1 and r2 obtain and release the lock "simultaneously"
|
||||
//2) either w1 or w2 obtains and releases the lock
|
||||
//3) the other of w1 and w2 obtains and releases the lock
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//The same, except that either w1 or w2 (but not both) may
|
||||
//fail to promote to a write lock.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
|
||||
{
|
||||
if (!test_promotion_and_demotion)
|
||||
{
|
||||
//Expected result:
|
||||
//1) either r1 or r2 obtains and releases the lock
|
||||
//2) either w1 or w2 obtains and releases the lock
|
||||
//3) the other of r1 and r2 obtains and releases the lock
|
||||
//4) the other of w1 and w2 obtains and release the lock
|
||||
TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0 || r1.value_ == 10, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0 || r2.value_ == 10, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ != r2.value_, MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Expected result:
|
||||
//Since w1 and w2 start as read locks, r1, r2, w1, and w2
|
||||
//obtain read locks "simultaneously". Each of w1 and w2,
|
||||
//after it obtain a read lock, attempts to promote to a
|
||||
//write lock; this attempt fails if the other has
|
||||
//already done so and currently holds the write lock;
|
||||
//otherwise it will succeed as soon as any other
|
||||
//read locks have been released.
|
||||
//In other words, any ordering is possible, and either
|
||||
//w1 or w2 (but not both) may fail to obtain the lock
|
||||
//altogether.
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0 || r1.value_ == 10 || r1.value_ == 20, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0 || r2.value_ == 10 || r2.value_ == 20, MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Verify that a read lock prevents readers but not writers from obtaining a lock
|
||||
{
|
||||
shared_val = 0;
|
||||
data<RW> r1(1, rw, 0, 0);
|
||||
data<RW> r2(2, rw, 0, 0);
|
||||
data<RW> w1(3, rw, 0, 0);
|
||||
data<RW> w2(4, rw, 0, 0);
|
||||
|
||||
//Read-lock the mutex and queue up other readers and writers
|
||||
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
|
||||
boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
|
||||
boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
//Expected result: all readers passed through before the writers entered
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
|
||||
if (test_promotion_and_demotion)
|
||||
{
|
||||
l.promote();
|
||||
}
|
||||
|
||||
l.unlock();
|
||||
|
||||
tr2.join();
|
||||
tr1.join();
|
||||
tw2.join();
|
||||
tw1.join();
|
||||
}
|
||||
|
||||
//Verify that a read lock prevents readers but not writers from obtaining a lock
|
||||
{
|
||||
shared_val = 0;
|
||||
data<RW> r1(1, rw, 0, 0);
|
||||
data<RW> r2(2, rw, 0, 0);
|
||||
data<RW> w1(3, rw, 0, 0);
|
||||
data<RW> w2(4, rw, 0, 0);
|
||||
|
||||
//Read-lock the mutex and queue up other readers and writers
|
||||
|
||||
typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
|
||||
boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
|
||||
boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
|
||||
|
||||
boost::thread::sleep(xsecs(1));
|
||||
|
||||
if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Writers have priority, so no readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
|
||||
{
|
||||
//Expected result:
|
||||
//Readers have priority, so all readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
|
||||
{
|
||||
//Expected result:
|
||||
//It's the writers' turn, so no readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
|
||||
{
|
||||
//Expected result:
|
||||
//It's the writers' turn, so no readers have been released
|
||||
TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
|
||||
TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
|
||||
}
|
||||
|
||||
if (test_promotion_and_demotion)
|
||||
{
|
||||
l.promote();
|
||||
}
|
||||
|
||||
l.unlock();
|
||||
|
||||
tr2.join();
|
||||
tr1.join();
|
||||
tw2.join();
|
||||
tw1.join();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void test_try_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
|
||||
{
|
||||
//Repeat the plain tests with the try lock.
|
||||
//This is important to verify that try locks are proper
|
||||
//read_write_mutexes as well.
|
||||
|
||||
test_plain_read_write_mutex(rw, test_promotion_and_demotion);
|
||||
|
||||
//Verify try_* operations with write-locked mutex
|
||||
{
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
|
||||
|
||||
shared_test_writelocked = true;
|
||||
shared_test_readlocked = false;
|
||||
shared_test_unlocked = false;
|
||||
|
||||
boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
|
||||
test_thread.join();
|
||||
}
|
||||
|
||||
//Verify try_* operations with read-locked mutex
|
||||
{
|
||||
typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
|
||||
|
||||
shared_test_writelocked = false;
|
||||
shared_test_readlocked = true;
|
||||
shared_test_unlocked = false;
|
||||
|
||||
boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
|
||||
test_thread.join();
|
||||
}
|
||||
|
||||
//Verify try_* operations with unlocked mutex
|
||||
{
|
||||
shared_test_writelocked = false;
|
||||
shared_test_readlocked = false;
|
||||
shared_test_unlocked = true;
|
||||
|
||||
boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
|
||||
test_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RW>
|
||||
void test_timed_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
|
||||
{
|
||||
//Repeat the try tests with the timed lock.
|
||||
//This is important to verify that timed locks are proper
|
||||
//try locks as well.
|
||||
|
||||
test_try_read_write_mutex(rw, test_promotion_and_demotion);
|
||||
|
||||
//:More tests here
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void do_test_read_write_mutex(bool test_promotion_and_demotion)
|
||||
{
|
||||
//Run every test for each scheduling policy
|
||||
|
||||
for(int i = (int) boost::read_write_scheduling_policy::writer_priority;
|
||||
i <= (int) boost::read_write_scheduling_policy::alternating_single_read;
|
||||
i++)
|
||||
{
|
||||
std::cout << "plain test, sp=" << i
|
||||
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
|
||||
<< "\n";
|
||||
std::cout.flush();
|
||||
|
||||
{
|
||||
boost::read_write_mutex plain_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
test_plain_read_write_mutex(plain_rw, test_promotion_and_demotion);
|
||||
}
|
||||
|
||||
std::cout << "try test, sp=" << i
|
||||
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
|
||||
<< "\n";
|
||||
std::cout.flush();
|
||||
|
||||
{
|
||||
boost::try_read_write_mutex try_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
test_try_read_write_mutex(try_rw, test_promotion_and_demotion);
|
||||
}
|
||||
|
||||
std::cout << "timed test, sp=" << i
|
||||
<< (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
|
||||
<< "\n";
|
||||
std::cout.flush();
|
||||
|
||||
{
|
||||
boost::timed_read_write_mutex timed_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
|
||||
test_timed_read_write_mutex(timed_rw, test_promotion_and_demotion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_read_write_mutex()
|
||||
{
|
||||
do_test_read_write_mutex(false);
|
||||
do_test_read_write_mutex(true);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: read_write_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_read_write_mutex));
|
||||
|
||||
return test;
|
||||
}
|
||||
460
test/test_shared_mutex.cpp
Normal file
460
test/test_shared_mutex.cpp
Normal file
@@ -0,0 +1,460 @@
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include "util.inl"
|
||||
|
||||
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
|
||||
{ \
|
||||
boost::mutex::scoped_lock lock(mutex_name); \
|
||||
BOOST_CHECK_EQUAL(value,expected_value); \
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename lock_type>
|
||||
class locking_thread
|
||||
{
|
||||
boost::shared_mutex& rw_mutex;
|
||||
unsigned& unblocked_count;
|
||||
unsigned& simultaneous_running_count;
|
||||
unsigned& max_simultaneous_running;
|
||||
boost::mutex& unblocked_count_mutex;
|
||||
boost::mutex& finish_mutex;
|
||||
public:
|
||||
locking_thread(boost::shared_mutex& rw_mutex_,
|
||||
unsigned& unblocked_count_,
|
||||
boost::mutex& unblocked_count_mutex_,
|
||||
boost::mutex& finish_mutex_,
|
||||
unsigned& simultaneous_running_count_,
|
||||
unsigned& max_simultaneous_running_):
|
||||
rw_mutex(rw_mutex_),
|
||||
unblocked_count(unblocked_count_),
|
||||
unblocked_count_mutex(unblocked_count_mutex_),
|
||||
finish_mutex(finish_mutex_),
|
||||
simultaneous_running_count(simultaneous_running_count_),
|
||||
max_simultaneous_running(max_simultaneous_running_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
// acquire lock
|
||||
lock_type lock(rw_mutex);
|
||||
|
||||
// increment count to show we're unblocked
|
||||
{
|
||||
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
|
||||
++unblocked_count;
|
||||
++simultaneous_running_count;
|
||||
if(simultaneous_running_count>max_simultaneous_running)
|
||||
{
|
||||
max_simultaneous_running=simultaneous_running_count;
|
||||
}
|
||||
}
|
||||
|
||||
// wait to finish
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
{
|
||||
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
|
||||
--simultaneous_running_count;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
void test_multiple_readers()
|
||||
{
|
||||
unsigned const number_of_threads=100;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
for(unsigned i=0;i<number_of_threads;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads);
|
||||
}
|
||||
|
||||
void test_only_one_writer_permitted()
|
||||
{
|
||||
unsigned const number_of_threads=100;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
for(unsigned i=0;i<number_of_threads;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1);
|
||||
}
|
||||
|
||||
void test_reader_blocks_writer()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1);
|
||||
}
|
||||
|
||||
void test_unlocking_writer_unblocks_all_readers()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::unique_lock<boost::shared_mutex> write_lock(rw_mutex);
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
unsigned const reader_count=100;
|
||||
|
||||
for(unsigned i=0;i<reader_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
|
||||
|
||||
write_lock.unlock();
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
|
||||
|
||||
finish_lock.unlock();
|
||||
pool.join_all();
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
|
||||
}
|
||||
|
||||
void test_unlocking_last_reader_only_unblocks_one_writer()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_readers=0;
|
||||
unsigned max_simultaneous_readers=0;
|
||||
unsigned simultaneous_running_writers=0;
|
||||
unsigned max_simultaneous_writers=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::mutex finish_reading_mutex;
|
||||
boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex);
|
||||
boost::mutex finish_writing_mutex;
|
||||
boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex);
|
||||
|
||||
unsigned const reader_count=100;
|
||||
unsigned const writer_count=100;
|
||||
|
||||
for(unsigned i=0;i<reader_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
|
||||
}
|
||||
for(unsigned i=0;i<writer_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
|
||||
}
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
|
||||
|
||||
finish_reading_lock.unlock();
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
|
||||
|
||||
finish_writing_lock.unlock();
|
||||
pool.join_all();
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1);
|
||||
}
|
||||
|
||||
void test_only_one_upgrade_lock_permitted()
|
||||
{
|
||||
unsigned const number_of_threads=100;
|
||||
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
for(unsigned i=0;i<number_of_threads;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
|
||||
boost::thread::sleep(delay(1));
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
|
||||
|
||||
finish_lock.unlock();
|
||||
|
||||
pool.join_all();
|
||||
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1);
|
||||
}
|
||||
|
||||
void test_can_lock_upgrade_if_currently_locked_shared()
|
||||
{
|
||||
boost::thread_group pool;
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
unsigned simultaneous_running_count=0;
|
||||
unsigned max_simultaneous_running=0;
|
||||
boost::mutex unblocked_count_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
|
||||
unsigned const reader_count=100;
|
||||
|
||||
for(unsigned i=0;i<reader_count;++i)
|
||||
{
|
||||
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
}
|
||||
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_mutex,simultaneous_running_count,max_simultaneous_running));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
|
||||
|
||||
finish_lock.unlock();
|
||||
pool.join_all();
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class simple_writing_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
public:
|
||||
simple_writing_thread(boost::shared_mutex& rwm_,
|
||||
boost::mutex& finish_mutex_,
|
||||
boost::mutex& unblocked_mutex_,
|
||||
unsigned& unblocked_count_):
|
||||
rwm(rwm_),finish_mutex(finish_mutex_),
|
||||
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::unique_lock<boost::shared_mutex> lk(rwm);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock ulk(unblocked_mutex);
|
||||
++unblocked_count;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock flk(finish_mutex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_shared();
|
||||
BOOST_CHECK(!try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
bool const try_succeeded=rw_mutex.try_lock_shared();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class simple_reading_thread
|
||||
{
|
||||
boost::shared_mutex& rwm;
|
||||
boost::mutex& finish_mutex;
|
||||
boost::mutex& unblocked_mutex;
|
||||
unsigned& unblocked_count;
|
||||
|
||||
public:
|
||||
simple_reading_thread(boost::shared_mutex& rwm_,
|
||||
boost::mutex& finish_mutex_,
|
||||
boost::mutex& unblocked_mutex_,
|
||||
unsigned& unblocked_count_):
|
||||
rwm(rwm_),finish_mutex(finish_mutex_),
|
||||
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lk(rwm);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock ulk(unblocked_mutex);
|
||||
++unblocked_count;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock flk(finish_mutex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
|
||||
{
|
||||
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1);
|
||||
|
||||
bool const try_succeeded=rw_mutex.try_lock_shared();
|
||||
BOOST_CHECK(try_succeeded);
|
||||
if(try_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
void test_timed_lock_shared_times_out_if_write_lock_held()
|
||||
{
|
||||
boost::shared_mutex rw_mutex;
|
||||
boost::mutex finish_mutex;
|
||||
boost::mutex unblocked_mutex;
|
||||
unsigned unblocked_count=0;
|
||||
boost::mutex::scoped_lock finish_lock(finish_mutex);
|
||||
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
|
||||
boost::thread::sleep(delay(1));
|
||||
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1);
|
||||
|
||||
boost::system_time const start=boost::get_system_time();
|
||||
boost::system_time const timeout=start+boost::posix_time::milliseconds(100);
|
||||
bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
|
||||
BOOST_CHECK(timeout<=boost::get_system_time());
|
||||
BOOST_CHECK(!timed_lock_succeeded);
|
||||
if(timed_lock_succeeded)
|
||||
{
|
||||
rw_mutex.unlock_shared();
|
||||
}
|
||||
|
||||
finish_lock.unlock();
|
||||
writer.join();
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_multiple_readers));
|
||||
test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted));
|
||||
test->add(BOOST_TEST_CASE(&test_reader_blocks_writer));
|
||||
test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers));
|
||||
test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer));
|
||||
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
|
||||
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
|
||||
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
|
||||
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
|
||||
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
|
||||
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
|
||||
|
||||
return test;
|
||||
}
|
||||
@@ -144,12 +144,11 @@ void do_test_tss()
|
||||
<< "\n";
|
||||
std::cout.flush();
|
||||
|
||||
// The following is not really an error. TSS cleanup support still is available
|
||||
// for threads, launched via the boost API. Also this usually will be triggered
|
||||
// only when bound to the static version of the thread lib.
|
||||
// 2006-10-15 Roland Schwarz
|
||||
// The following is not really an error. TSS cleanup support still is available for boost threads.
|
||||
// Also this usually will be triggered only when bound to the static version of thread lib.
|
||||
// 2006-10-02 Roland Schwarz
|
||||
//BOOST_CHECK_EQUAL(tss_instances, 0);
|
||||
BOOST_CHECK_MESSAGE(tss_instances ==0, "Support of automatic tss cleanup for native threading API not available");
|
||||
BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
|
||||
BOOST_CHECK_EQUAL(tss_total, 5);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
|
||||
#endif
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace
|
||||
{
|
||||
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
# Copyright (C) 2001-2003
|
||||
# William E. Kempf
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Boost.Threads tutorial Jamfile
|
||||
#
|
||||
# Additional configuration variables used:
|
||||
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
|
||||
# library should be used instead of "native" threads. This feature is
|
||||
# mostly used for testing and it's generally recommended you use the
|
||||
# native threading libraries instead. PTW32 should be set to be a list
|
||||
# of two strings, the first specifying the installation path of the
|
||||
# pthreads-win32 library and the second specifying which library
|
||||
# variant to link against (see the pthreads-win32 documentation).
|
||||
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
|
||||
|
||||
project
|
||||
: requirements <library>/boost/thread//boost_thread
|
||||
<threading>multi
|
||||
;
|
||||
|
||||
exe helloworld : helloworld.cpp ;
|
||||
exe helloworld2 : helloworld2.cpp ;
|
||||
exe helloworld3 : helloworld3.cpp ;
|
||||
exe helloworld4 : helloworld4.cpp ;
|
||||
exe factorial : factorial.cpp ;
|
||||
exe factorial2 : factorial2.cpp ;
|
||||
exe factorial3 : factorial3.cpp ;
|
||||
exe counter : counter.cpp ;
|
||||
exe bounded_buffer : bounded_buffer.cpp ;
|
||||
exe once : once.cpp ;
|
||||
|
||||
Reference in New Issue
Block a user