2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 09:42:16 +00:00

Compare commits

...

41 Commits

Author SHA1 Message Date
Daniel James
c86959afb7 Fix links to the license text file.
[SVN r43289]
2008-02-17 12:49:59 +00:00
Daniel James
8b302dbb4f More fixed links.
[SVN r43279]
2008-02-16 11:39:55 +00:00
Daniel James
43943faf5c Merge.
[SVN r43162]
2008-02-07 18:54:14 +00:00
Daniel James
f934c01bdf Merge.
[SVN r42905]
2008-01-21 20:15:02 +00:00
Daniel James
5af025cdce Merge from trunk.
[SVN r42243]
2007-12-22 15:36:31 +00:00
Daniel James
1b56fe63d1 Merge from trunk.
[SVN r41865]
2007-12-08 11:05:02 +00:00
Daniel James
d460417a09 Merge from trunk, finally.
[SVN r41817]
2007-12-07 01:12:02 +00:00
Daniel James
67ce920ab8 Create a branch to fix links on.
[SVN r41573]
2007-12-02 10:07:42 +00:00
Anthony Williams
b50a7ccb61 interruptible_wait (and hence condition timed_wait) now uses a WaitableTimer where possible, to be robust in the face of clock changes
[SVN r41505]
2007-11-30 18:38:21 +00:00
Anthony Williams
f827709d42 add support for relative timeouts to condition timed_wait
[SVN r41413]
2007-11-27 14:24:29 +00:00
Anthony Williams
36abb42175 reverted accidental checkin of new timed_wait functions on condition_variable
[SVN r41405]
2007-11-26 21:15:04 +00:00
Anthony Williams
40f3b1b4c8 once_flag uses zero-initialization on POSIX as well as windows
[SVN r41401]
2007-11-26 17:01:08 +00:00
Anthony Williams
4f35e25688 fixed import/export declarations so new once code works with pthread-win32
[SVN r41398]
2007-11-26 15:44:07 +00:00
Anthony Williams
270e88edd7 Don't compare native_handle_t against 0 --- do appropriate checks in create_native_thread for platforms where pthread_t is not comparable
[SVN r41396]
2007-11-26 13:29:15 +00:00
Anthony Williams
5ded171247 workaround for Borland compiler
[SVN r41395]
2007-11-26 12:17:45 +00:00
Anthony Williams
332dd988e4 Integrate TSS with thread data; test to ensure cleanup done for native threads as well as boost::thread-launched threads now runs for pthread API as well as win32 API
[SVN r41320]
2007-11-23 23:09:36 +00:00
Anthony Williams
bce8db41d7 Removed thread::self in favour of allowing interruption through a thread::id; no longer requires DuplicateHandle
[SVN r41311]
2007-11-22 22:01:30 +00:00
Anthony Williams
f6fd70245d changed platform split to allow bjam to track includes and check dependencies
[SVN r41273]
2007-11-21 10:44:22 +00:00
Anthony Williams
4ff0a055d6 added copyright
[SVN r41226]
2007-11-19 14:29:22 +00:00
Anthony Williams
c9140267a5 fixed problems with TSS cleanup when using LoadLibrary and when threads finish after thread_specific_ptr instance has been destroyed
[SVN r41223]
2007-11-19 12:29:14 +00:00
Anthony Williams
72fcee4e5e fixed TSS cleanup on 64-bit Windows
[SVN r41222]
2007-11-19 12:17:31 +00:00
Beman Dawes
9c8e512edd // Add or correct comment identifying Boost library this header is associated with.
[SVN r41173]
2007-11-17 20:13:16 +00:00
Anthony Williams
3c191af34a New implementation of pthread_once based on Mike Burrows' algorithm
[SVN r41160]
2007-11-16 22:51:52 +00:00
Beman Dawes
5e0b2d7370 Get rid of .cvsignore files
[SVN r41107]
2007-11-15 15:20:27 +00:00
Anthony Williams
5994abd453 fixes for pthread implementation
[SVN r41090]
2007-11-14 14:49:58 +00:00
Anthony Williams
67a2d119c0 interrupt and join all threads in a group if an exception is thrown during a test
[SVN r41087]
2007-11-14 12:17:41 +00:00
Anthony Williams
114215088a interrupt and join all threads in a group if an exception is thrown during a test
[SVN r41084]
2007-11-14 11:56:53 +00:00
Anthony Williams
a78e2b793e ignore and join all threads in group on exception
[SVN r41083]
2007-11-14 11:08:09 +00:00
Anthony Williams
519ed3834e Integrated TSS with storage of thread data; cleaned up the heap allocation functions to throw bad_alloc if they run out of memory
[SVN r41056]
2007-11-13 09:27:11 +00:00
Roland Schwarz
22647135fa Added static linking support for mingw compiler on windows.
[SVN r40999]
2007-11-10 19:25:45 +00:00
Roland Schwarz
58c741e9ca Reverted the previous commit, until I find a better solution...
[SVN r40959]
2007-11-09 09:28:29 +00:00
Roland Schwarz
ef9083089e Force static linking for toolsets mingw and boorland.
[SVN r40958]
2007-11-09 08:31:45 +00:00
Anthony Williams
5de1582a0a Added missing licence and copyright
[SVN r40884]
2007-11-07 12:10:17 +00:00
Anthony Williams
39c864e31f use condition so we know when threads have unblocked, to avoid hard-coding a delay
[SVN r40846]
2007-11-06 17:15:50 +00:00
Anthony Williams
320cb63df4 Use BOOST_VERIFY instead of BOOST_ASSERT in many places in order to avoid unused variable warnings
[SVN r40792]
2007-11-05 16:47:25 +00:00
Roland Schwarz
c246222ded Cosmetic change to please gcc.
[SVN r40791]
2007-11-05 16:22:17 +00:00
Roland Schwarz
b7edb2873c Usage requirements added.
[SVN r40790]
2007-11-05 16:12:49 +00:00
Anthony Williams
89f2032c0d Use pthread_equal for comparing pthread_t IDs; use BOOST_VERIFY instead of BOOST_ASSERT in many places in order to avoid unused variable warnings
[SVN r40787]
2007-11-05 14:16:21 +00:00
Anthony Williams
d2f8230093 threadapi is a composite feature again
[SVN r40774]
2007-11-05 10:15:24 +00:00
Roland Schwarz
9f6b5d169a Get rid of "unsused variable" warnings by making use of BOOST_VERIFY.
This changeset is for pthread only.


[SVN r40742]
2007-11-04 17:17:01 +00:00
Anthony Williams
e56708d4aa added missing include
[SVN r40730]
2007-11-03 22:00:12 +00:00
92 changed files with 3114 additions and 1819 deletions

View File

@@ -1,2 +0,0 @@
bin*
*.pdb

View File

@@ -75,71 +75,102 @@ rule tag ( name : type ? : property-set )
$(result) : $(type) : $(property-set) ] ;
}
rule win32_pthread_paths ( properties * )
{
local result ;
local PTW32_INCLUDE ;
local PTW32_LIB ;
PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
rule requirements ( properties * )
if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
{
if ! $(.notified)
{
echo "************************************************************" ;
echo "Trying to build Boost.Thread with pthread support." ;
echo "If you need pthread you should specify the paths." ;
echo "You can specify them in site-config.jam, user-config.jam" ;
echo "or in the environment." ;
echo "For example:" ;
echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
echo "************************************************************" ;
.notified = true ;
}
}
else
{
local include_path = [ path.make $(PTW32_INCLUDE) ] ;
local lib_path = [ path.make $(PTW32_LIB) ] ;
local libname = pthread ;
if <toolset>msvc in $(properties)
{
libname = $(libname)VC2.lib ;
}
if <toolset>gcc in $(properties)
{
libname = lib$(libname)GC2.a ;
}
lib_path = [ path.glob $(lib_path) : $(libname) ] ;
if ! $(lib_path)
{
if ! $(.notified)
{
echo "************************************************************" ;
echo "Trying to build Boost.Thread with pthread support." ;
echo "But the library" $(libname) "could not be found in path" ;
echo $(PTW32_LIB) ;
echo "************************************************************" ;
.notified = true ;
}
}
else
{
result += <include>$(include_path) ;
result += <library>$(lib_path) ;
}
}
return $(result) ;
}
rule usage-requirements ( properties * )
{
local result ;
if <threadapi>pthread in $(properties)
{
result += <define>BOOST_THREAD_POSIX ;
if <target-os>windows in $(properties)
{
result += [ win32_pthread_paths $(properties) ] ;
# TODO: What is for static linking? Is the <library> also needed
# in that case?
}
}
return $(result) ;
}
rule requirements ( properties * )
{
local result ;
if <threadapi>pthread in $(properties)
{
result += <define>BOOST_THREAD_POSIX ;
if <target-os>windows in $(properties)
{
local PTW32_INCLUDE ;
local PTW32_LIB ;
PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
local paths = [ win32_pthread_paths $(properties) ] ;
if $(paths)
{
if ! $(.notified)
{
echo "************************************************************" ;
echo "Trying to build Boost.Thread with pthread support." ;
echo "If you need pthread you should specify the paths." ;
echo "You can specify them in site-config.jam, user-config.jam" ;
echo "or in the environment." ;
echo "For example:" ;
echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
echo "************************************************************" ;
.notified = true ;
}
result = <build>no ;
result += $(paths) ;
}
else
{
local include_path = [ path.make $(PTW32_INCLUDE) ] ;
local lib_path = [ path.make $(PTW32_LIB) ] ;
result += <include>$(include_path) ;
local libname = pthread ;
if <toolset>msvc in $(properties)
{
libname = $(libname)VC2.lib ;
}
if <toolset>gcc in $(properties)
{
libname = lib$(libname)GC2.a ;
}
lib_path = [ path.glob $(lib_path) : $(libname) ] ;
if ! $(lib_path)
{
if ! $(.notified)
{
echo "************************************************************" ;
echo "Trying to build Boost.Thread with pthread support." ;
echo "But the library" $(libname) "could not be found in path" ;
echo $(PTW32_LIB) ;
echo "************************************************************" ;
.notified = true ;
}
result = <build>no ;
}
result += <library>$(lib_path) ;
result = <build>no ;
}
}
}
@@ -150,8 +181,6 @@ alias thread_sources
: ## win32 sources ##
win32/thread.cpp
win32/exceptions.cpp
win32/tss.cpp
win32/tss_hooks.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
: ## requirements ##
@@ -162,7 +191,7 @@ alias thread_sources
: ## pthread sources ##
pthread/thread.cpp
pthread/exceptions.cpp
pthread/tss.cpp
pthread/once.cpp
: ## requirements ##
<threadapi>pthread
;
@@ -172,4 +201,8 @@ explicit thread_sources ;
lib boost_thread
: thread_sources
: <conditional>@requirements
:
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
<link>static:<define>BOOST_THREAD_USE_LIB=1
<conditional>@usage-requirements
;

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.acknowledgements"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/barrier.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<bibliography id="thread.bibliography"
last-revision="$Date$">
@@ -45,7 +45,7 @@ last-revision="$Date$">
<biblioentry id="thread.bib.Boost">
<abbrev id="thread.bib.Boost.abbrev">Boost</abbrev>
<bibliomisc>The <emphasis>Boost</emphasis> world wide web site.
<ulink url="http:/www.boost.org">http://www.boost.org</ulink></bibliomisc>
<ulink url="http://www.boost.org">http://www.boost.org</ulink></bibliomisc>
<para>&Boost.Thread; is one of many Boost libraries. The Boost web
site includes a great deal of documentation and general information which
applies to all Boost libraries. Current copies of the libraries including

View File

@@ -7,7 +7,7 @@
<!-- 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)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.build" last-revision="$Date$">
<title>Build</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.concepts" last-revision="$Date$">
<title>Concepts</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/condition.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.configuration" last-revision="$Date$">
<title>Configuration</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.design" last-revision="$Date$">
<title>Design</title>

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<!ENTITY Boost "<emphasis role='bold'>Boost</emphasis>">
<!ENTITY Boost.Thread "<emphasis role='bold'>Boost.Thread</emphasis>">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/exceptions.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.faq" last-revision="$Date$">
<title>Frequently Asked Questions</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<glossary id="thread.glossary" last-revision="$Date$">
<title>Glossary</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.implementation_notes" last-revision="$Date$">
<title>Implementation Notes</title>

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<html>
<head>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/mutex.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/once.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.overview" last-revision="$Date$">
<title>Overview</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.rationale" last-revision="$Date$">
<title>Rationale</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/read_write_mutex.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/recursive_mutex.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<library-reference id="thread.reference"
last-revision="$Date$"

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="thread.release_notes" last-revision="$Date$">
<title>Release Notes</title>

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/thread.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<library name="Thread" dirname="thread" id="thread"
last-revision="$Date$"
@@ -25,7 +25,7 @@ xmlns:xi="http://www.w3.org/2001/XInclude">
</copyright>
<legalnotice>
<para>Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)</para>
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)</para>
</legalnotice>
<librarypurpose>Portable C++ multi-threading</librarypurpose>
<librarycategory name="category:concurrent" />

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/tss.hpp"
last-revision="$Date$">

View File

@@ -6,7 +6,7 @@
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<header name="boost/thread/xtime.hpp"
last-revision="$Date$">

View File

@@ -1,2 +0,0 @@
bin
*.pdb

View File

@@ -4,6 +4,8 @@
// 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)
// See www.boost.org/libs/thread for documentation.
#if !defined(BOOST_THREAD_WEK01082003_HPP)
#define BOOST_THREAD_WEK01082003_HPP

View File

@@ -1,5 +1,11 @@
#ifndef BOOST_THREAD_CONDITION_HPP
#define BOOST_THREAD_CONDITION_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/condition_variable.hpp>
namespace boost

View File

@@ -10,6 +10,12 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(condition_variable.hpp)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/condition_variable.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/condition_variable.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -17,8 +17,7 @@
# pragma warn -8066 // Unreachable code
#endif
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
#include "platform.hpp"
// compatibility with the rest of Boost's auto-linking code:
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
@@ -31,7 +30,7 @@
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
#else //Use default
# if defined(BOOST_HAS_WINTHREADS)
# if defined(BOOST_THREAD_PLATFORM_WIN32)
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
//For compilers supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads lib

View File

@@ -8,25 +8,23 @@
namespace boost
{
template<typename T>
struct move_t
namespace detail
{
T& t;
move_t(T& t_):
t(t_)
{}
T* operator->() const
template<typename T>
struct thread_move_t
{
return &t;
}
};
T& t;
thread_move_t(T& t_):
t(t_)
{}
template<typename T>
move_t<T> move(T& t)
{
return move_t<T>(t);
T* operator->() const
{
return &t;
}
};
}
}

View File

@@ -1,4 +1,5 @@
// Copyright 2006 Roland Schwarz.
// (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)
@@ -56,17 +57,15 @@
// available the preprocessor will fail with a diagnostic message.
#if defined(BOOST_THREAD_POSIX)
# define BOOST_THREAD_PPFX pthread
# define BOOST_THREAD_PLATFORM_PTHREAD
#else
# if defined(BOOST_THREAD_WIN32)
# define BOOST_THREAD_PPFX win32
# define BOOST_THREAD_PLATFORM_WIN32
# elif defined(BOOST_HAS_PTHREADS)
# define BOOST_THREAD_PPFX pthread
# define BOOST_THREAD_PLATFORM_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

View File

@@ -67,7 +67,7 @@
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" void tss_cleanup_implemented(void);
//Dummy function used both to detect whether tss cleanup
//cleanup has been implemented and to force

View File

@@ -86,21 +86,32 @@ namespace boost
{
timed_lock(target_time);
}
unique_lock(boost::move_t<unique_lock<Mutex> > other):
unique_lock(detail::thread_move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
other->m=0;
}
unique_lock(boost::move_t<upgrade_lock<Mutex> > other);
unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other);
unique_lock& operator=(boost::move_t<unique_lock<Mutex> > other)
operator detail::thread_move_t<unique_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<unique_lock<Mutex> > move()
{
return detail::thread_move_t<unique_lock<Mutex> >(*this);
}
unique_lock& operator=(detail::thread_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& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
{
unique_lock temp(other);
swap(temp);
@@ -112,7 +123,7 @@ namespace boost
std::swap(m,other.m);
std::swap(is_locked,other.is_locked);
}
void swap(boost::move_t<unique_lock<Mutex> > other)
void swap(detail::thread_move_t<unique_lock<Mutex> > other)
{
std::swap(m,other->m);
std::swap(is_locked,other->is_locked);
@@ -196,6 +207,18 @@ namespace boost
friend class upgrade_lock<Mutex>;
};
template<typename Mutex>
inline detail::thread_move_t<unique_lock<Mutex> > move(unique_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<unique_lock<Mutex> > move(detail::thread_move_t<unique_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
class shared_lock
{
@@ -228,13 +251,13 @@ namespace boost
timed_lock(target_time);
}
shared_lock(boost::move_t<shared_lock<Mutex> > other):
shared_lock(detail::thread_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):
shared_lock(detail::thread_move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -244,7 +267,7 @@ namespace boost
}
}
shared_lock(boost::move_t<upgrade_lock<Mutex> > other):
shared_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -254,21 +277,32 @@ namespace boost
}
}
shared_lock& operator=(boost::move_t<shared_lock<Mutex> > other)
operator detail::thread_move_t<shared_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<shared_lock<Mutex> > move()
{
return detail::thread_move_t<shared_lock<Mutex> >(*this);
}
shared_lock& operator=(detail::thread_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& operator=(detail::thread_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& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
{
shared_lock temp(other);
swap(temp);
@@ -341,6 +375,19 @@ namespace boost
};
template<typename Mutex>
inline detail::thread_move_t<shared_lock<Mutex> > move(shared_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<shared_lock<Mutex> > move(detail::thread_move_t<shared_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
class upgrade_lock
{
@@ -364,13 +411,13 @@ namespace boost
lock();
}
}
upgrade_lock(boost::move_t<upgrade_lock<Mutex> > other):
upgrade_lock(detail::thread_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):
upgrade_lock(detail::thread_move_t<unique_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -380,14 +427,25 @@ namespace boost
}
}
upgrade_lock& operator=(boost::move_t<upgrade_lock<Mutex> > other)
operator detail::thread_move_t<upgrade_lock<Mutex> >()
{
return move();
}
detail::thread_move_t<upgrade_lock<Mutex> > move()
{
return detail::thread_move_t<upgrade_lock<Mutex> >(*this);
}
upgrade_lock& operator=(detail::thread_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& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
{
upgrade_lock temp(other);
swap(temp);
@@ -452,8 +510,21 @@ namespace boost
friend class unique_lock<Mutex>;
};
template<typename Mutex>
unique_lock<Mutex>::unique_lock(boost::move_t<upgrade_lock<Mutex> > other):
inline detail::thread_move_t<upgrade_lock<Mutex> > move(upgrade_lock<Mutex> & x)
{
return x.move();
}
template<typename Mutex>
inline detail::thread_move_t<upgrade_lock<Mutex> > move(detail::thread_move_t<upgrade_lock<Mutex> > x)
{
return x;
}
template<typename Mutex>
unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
m(other->m),is_locked(other->is_locked)
{
other->is_locked=false;
@@ -474,23 +545,23 @@ namespace boost
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))
source(&m_),exclusive(move(*source))
{}
~upgrade_to_unique_lock()
{
if(source)
{
*source=boost::move(exclusive);
*source=move(exclusive);
}
}
upgrade_to_unique_lock(boost::move_t<upgrade_to_unique_lock<Mutex> > other):
source(other->source),exclusive(boost::move(other->exclusive))
upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other):
source(other->source),exclusive(move(other->exclusive))
{
other->source=0;
}
upgrade_to_unique_lock& operator=(boost::move_t<upgrade_to_unique_lock<Mutex> > other)
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other)
{
upgrade_to_unique_lock temp(other);
swap(temp);
@@ -515,6 +586,7 @@ namespace boost
return exclusive.owns_lock();
}
};
}
#endif

View File

@@ -10,6 +10,12 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(mutex.hpp)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -10,7 +10,13 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(once.hpp)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/once.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/once.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
namespace boost
{

View File

@@ -5,11 +5,9 @@
// 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_time.hpp>
#include <pthread.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
@@ -28,15 +26,13 @@ namespace boost
}
inline condition_variable::~condition_variable()
{
int const res=pthread_cond_destroy(&cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}
inline void condition_variable::wait(unique_lock<mutex>& m)
{
detail::interruption_checker check_for_interruption(&cond);
int const cond_res=pthread_cond_wait(&cond,m.mutex()->native_handle());
BOOST_ASSERT(!cond_res);
BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle()));
}
inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
@@ -54,14 +50,12 @@ namespace boost
inline void condition_variable::notify_one()
{
int const res=pthread_cond_signal(&cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
inline void condition_variable::notify_all()
{
int const res=pthread_cond_broadcast(&cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
}
class condition_variable_any
@@ -83,17 +77,14 @@ namespace boost
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
int const destroy_res=pthread_mutex_destroy(&internal_mutex);
BOOST_ASSERT(!destroy_res);
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
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);
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}
template<typename lock_type>
@@ -152,23 +143,33 @@ namespace boost
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
return pred();
}
return true;
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
{
return timed_wait(m,get_system_time()+wait_duration,pred);
}
void notify_one()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
int const res=pthread_cond_signal(&cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
void notify_all()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
int const res=pthread_cond_broadcast(&cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
}
};

View File

@@ -6,8 +6,10 @@
// (C) Copyright 2007 Anthony Williams
#include <pthread.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -39,11 +41,23 @@ namespace boost
while (!pred())
{
if(!timed_wait(m, wait_until))
return false;
return pred();
}
return true;
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return timed_wait(m,get_system_time()+wait_duration,pred);
}
void notify_one();
void notify_all();
};

View File

@@ -42,20 +42,17 @@ namespace boost
}
~mutex()
{
int const res=pthread_mutex_destroy(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_destroy(&m));
}
void lock()
{
int const res=pthread_mutex_lock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
int const res=pthread_mutex_unlock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
@@ -98,8 +95,7 @@ namespace boost
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
int const destroy_res=pthread_mutex_destroy(&m);
BOOST_ASSERT(!destroy_res);
BOOST_VERIFY(!pthread_mutex_destroy(&m));
throw thread_resource_error();
}
is_locked=false;
@@ -107,11 +103,9 @@ namespace boost
}
~timed_mutex()
{
int const res=pthread_mutex_destroy(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
int const res2=pthread_cond_destroy(&cond);
BOOST_ASSERT(!res2);
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
}
@@ -124,14 +118,12 @@ namespace boost
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
void lock()
{
int const res=pthread_mutex_lock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
int const res=pthread_mutex_unlock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
@@ -153,8 +145,7 @@ namespace boost
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);
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
}
is_locked=true;
}
@@ -163,8 +154,7 @@ namespace boost
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
is_locked=false;
int const res=pthread_cond_signal(&cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
bool try_lock()

View File

@@ -13,62 +13,73 @@
#include <pthread.h>
#include <boost/assert.hpp>
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/cstdint.hpp>
namespace boost {
struct once_flag
{
pthread_mutex_t mutex;
unsigned flag;
boost::uintmax_t epoch;
};
#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);
}
};
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
}
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
// Based on Mike Burrows fast_pthread_once algorithm as described in
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
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)
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
boost::uintmax_t const epoch=flag.epoch;
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
if(epoch<this_thread_epoch)
{
#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
}
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
while(flag.epoch<=being_initialized)
{
if(flag.epoch==uninitialized_flag)
{
flag.epoch=being_initialized;
try
{
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
f();
}
catch(...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
throw;
}
flag.epoch=--detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
}
}
}
this_thread_epoch=detail::once_global_epoch;
}
}
}
#endif

View File

@@ -1,5 +1,11 @@
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_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/assert.hpp>
@@ -14,13 +20,27 @@ namespace boost
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
m(m_)
{
int const res=pthread_mutex_lock(m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_lock(m));
}
~pthread_mutex_scoped_lock()
{
int const res=pthread_mutex_unlock(m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
};
class pthread_mutex_scoped_unlock
{
pthread_mutex_t* m;
public:
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
m(m_)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
~pthread_mutex_scoped_unlock()
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
};

View File

@@ -53,25 +53,21 @@ namespace boost
{
throw thread_resource_error();
}
int const destroy_attr_res=pthread_mutexattr_destroy(&attr);
BOOST_ASSERT(!destroy_attr_res);
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
}
~recursive_mutex()
{
int const res=pthread_mutex_destroy(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_destroy(&m));
}
void lock()
{
int const res=pthread_mutex_lock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
int const res=pthread_mutex_unlock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
@@ -117,12 +113,10 @@ namespace boost
int const res=pthread_mutex_init(&m,&attr);
if(res)
{
int const destroy_attr_res=pthread_mutexattr_destroy(&attr);
BOOST_ASSERT(!destroy_attr_res);
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
throw thread_resource_error();
}
int const destroy_attr_res=pthread_mutexattr_destroy(&attr);
BOOST_ASSERT(!destroy_attr_res);
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
#else
int const res=pthread_mutex_init(&m,NULL);
if(res)
@@ -132,8 +126,7 @@ namespace boost
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
int const destroy_res=pthread_mutex_destroy(&m);
BOOST_ASSERT(!destroy_res);
BOOST_VERIFY(!pthread_mutex_destroy(&m));
throw thread_resource_error();
}
is_locked=false;
@@ -142,11 +135,9 @@ namespace boost
}
~recursive_timed_mutex()
{
int const res=pthread_mutex_destroy(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
int const res2=pthread_cond_destroy(&cond);
BOOST_ASSERT(!res2);
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
}
@@ -159,14 +150,12 @@ namespace boost
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
void lock()
{
int const res=pthread_mutex_lock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
int const res=pthread_mutex_unlock(&m);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
@@ -186,7 +175,7 @@ namespace boost
void lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && owner==pthread_self())
if(is_locked && pthread_equal(owner,pthread_self()))
{
++count;
return;
@@ -194,8 +183,7 @@ namespace boost
while(is_locked)
{
int const cond_res=pthread_cond_wait(&cond,&m);
BOOST_ASSERT(!cond_res);
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
}
is_locked=true;
++count;
@@ -209,14 +197,13 @@ namespace boost
{
is_locked=false;
}
int const res=pthread_cond_signal(&cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
bool try_lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && owner!=pthread_self())
if(is_locked && !pthread_equal(owner,pthread_self()))
{
return false;
}
@@ -230,7 +217,7 @@ namespace boost
{
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())
if(is_locked && pthread_equal(owner,pthread_self()))
{
++count;
return true;

View File

@@ -10,6 +10,7 @@
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/condition_variable.hpp>
namespace boost

View File

@@ -33,51 +33,69 @@ namespace boost
namespace this_thread
{
detail::thread_id get_id();
BOOST_THREAD_DECL detail::thread_id get_id();
}
namespace detail
{
class thread_id
{
boost::optional<pthread_t> id;
private:
detail::thread_data_ptr thread_data;
thread_id(detail::thread_data_ptr thread_data_):
thread_data(thread_data_)
{}
friend class boost::thread;
friend thread_id this_thread::get_id();
thread_id(pthread_t id_):
id(id_)
{}
public:
thread_id()
thread_id():
thread_data()
{}
bool operator==(const thread_id& y) const
{
return (id && y.id) && (pthread_equal(*id,*y.id)!=0);
return thread_data==y.thread_data;
}
bool operator!=(const thread_id& y) const
{
return !(*this==y);
return thread_data!=y.thread_data;
}
bool operator<(const thread_id& y) const
{
return thread_data<y.thread_data;
}
bool operator>(const thread_id& y) const
{
return y.thread_data<thread_data;
}
bool operator<=(const thread_id& y) const
{
return !(y.thread_data<thread_data);
}
bool operator>=(const thread_id& y) const
{
return !(thread_data<y.thread_data);
}
template<class charT, class traits>
friend std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const thread_id& x)
{
if(x.id)
if(x.thread_data)
{
return os<<*x.id;
return os<<x.thread_data;
}
else
{
return os<<"{Not-any-thread}";
}
}
};
}
@@ -97,7 +115,7 @@ namespace boost
thread_data(F f_):
f(f_)
{}
thread_data(boost::move_t<F> f_):
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
@@ -108,13 +126,13 @@ namespace boost
};
mutable boost::mutex thread_info_mutex;
boost::shared_ptr<detail::thread_data_base> thread_info;
detail::thread_data_ptr thread_info;
void start_thread();
explicit thread(boost::shared_ptr<detail::thread_data_base> data);
explicit thread(detail::thread_data_ptr data);
boost::shared_ptr<detail::thread_data_base> get_thread_info() const;
detail::thread_data_ptr get_thread_info() const;
public:
thread();
@@ -127,16 +145,16 @@ namespace boost
start_thread();
}
template <class F>
thread(boost::move_t<F> f):
thread(detail::thread_move_t<F> f):
thread_info(new thread_data<F>(f))
{
start_thread();
}
explicit thread(boost::move_t<thread> x);
thread& operator=(boost::move_t<thread> x);
operator boost::move_t<thread>();
boost::move_t<thread> move();
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> move();
void swap(thread& x);
@@ -169,6 +187,17 @@ namespace boost
bool interruption_requested() const;
};
inline detail::thread_move_t<thread> move(thread& x)
{
return x.move();
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
{
return x;
}
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
detail::thread_data_base
@@ -208,14 +237,11 @@ namespace boost
~restore_interruption();
};
inline thread::id get_id()
{
return thread::id(pthread_self());
}
BOOST_THREAD_DECL thread::id get_id();
void BOOST_THREAD_DECL interruption_point();
bool BOOST_THREAD_DECL interruption_enabled();
bool BOOST_THREAD_DECL interruption_requested();
BOOST_THREAD_DECL void interruption_point();
BOOST_THREAD_DECL bool interruption_enabled();
BOOST_THREAD_DECL bool interruption_requested();
inline void yield()
{
@@ -254,13 +280,13 @@ namespace boost
}
};
void add_thread_exit_function(thread_exit_function_base*);
BOOST_THREAD_DECL void add_thread_exit_function(thread_exit_function_base*);
}
namespace this_thread
{
template<typename F>
void at_thread_exit(F f)
inline void at_thread_exit(F f)
{
detail::thread_exit_function_base* const thread_exit_func=new detail::thread_exit_function<F>(f);
detail::add_thread_exit_function(thread_exit_func);
@@ -277,6 +303,7 @@ namespace boost
void add_thread(thread* thrd);
void remove_thread(thread* thrd);
void join_all();
void interrupt_all();
int size() const;
private:

View File

@@ -7,6 +7,7 @@
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/optional.hpp>
#include <pthread.h>
@@ -20,10 +21,15 @@ namespace boost
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base;
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
struct thread_data_base
struct thread_data_base:
enable_shared_from_this<thread_data_base>
{
boost::shared_ptr<thread_data_base> self;
thread_data_ptr self;
pthread_t thread_handle;
boost::mutex data_mutex;
boost::condition_variable done_condition;
@@ -33,13 +39,14 @@ namespace boost
bool join_started;
bool joined;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interrupt_enabled;
bool interrupt_requested;
pthread_cond_t* current_cond;
thread_data_base():
done(false),join_started(false),joined(false),
thread_exit_callbacks(0),
thread_exit_callbacks(0),tss_data(0),
interrupt_enabled(true),
interrupt_requested(false),
current_cond(0)

View File

@@ -1,5 +1,10 @@
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
#define BOOST_THREAD_PTHREAD_TIMESPEC_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/thread_time.hpp>
#include <boost/date_time/posix_time/conversion.hpp>

View File

@@ -0,0 +1,103 @@
#ifndef BOOST_THREAD_PTHREAD_TSS_HPP
#define BOOST_THREAD_PTHREAD_TSS_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/detail/config.hpp>
#include <boost/shared_ptr.hpp>
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(data);
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(new delete_data)
{}
explicit thread_specific_ptr(void (*func_)(T*)):
cleanup(new run_custom_cleanup_function(func_))
{}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,0,0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#endif

View File

@@ -10,6 +10,12 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(recursive_mutex.hpp)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/recursive_mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/recursive_mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -10,6 +10,12 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(shared_mutex.hpp)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/shared_mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/shared_mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -10,6 +10,13 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(thread.hpp)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/thread.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/thread.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -1,5 +1,11 @@
#ifndef BOOST_THREAD_TIME_HPP
#define BOOST_THREAD_TIME_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/date_time/microsec_time_clock.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>

View File

@@ -1,128 +1,18 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// 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)
#ifndef BOOST_TSS_WEK070601_HPP
#define BOOST_TSS_WEK070601_HPP
#ifndef BOOST_THREAD_TSS_HPP
#define BOOST_THREAD_TSS_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/tss.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/tss.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
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 detail {
class BOOST_THREAD_DECL tss : private noncopyable
{
public:
tss(boost::function1<void, void*>* pcleanup) {
if (pcleanup == 0) throw boost::thread_resource_error();
try
{
init(pcleanup);
}
catch (...)
{
delete pcleanup;
throw boost::thread_resource_error();
}
}
~tss();
void* get() const;
void set(void* value);
void cleanup(void* p);
private:
unsigned int m_slot; //This is a "pseudo-slot", not a native slot
void init(boost::function1<void, void*>* pcleanup);
};
#if defined(BOOST_HAS_MPTASKS)
void thread_cleanup();
#endif
template <typename T>
struct tss_adapter
{
template <typename F>
tss_adapter(const F& cleanup) : m_cleanup(cleanup) { }
void operator()(void* p) { m_cleanup(static_cast<T*>(p)); }
boost::function1<void, T*> m_cleanup;
};
} // namespace detail
template <typename T>
class thread_specific_ptr : private noncopyable
{
public:
thread_specific_ptr()
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(
&thread_specific_ptr<T>::cleanup)))
{
}
thread_specific_ptr(void (*clean)(T*))
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(clean)))
{
}
~thread_specific_ptr() { reset(); }
T* get() const { return static_cast<T*>(m_tss.get()); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; }
void reset(T* p=0)
{
T* cur = get();
if (cur == p) return;
m_tss.set(p);
if (cur) m_tss.cleanup(cur);
}
private:
static void cleanup(T* p) { delete p; }
detail::tss m_tss;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif //BOOST_TSS_WEK070601_HPP
// Change Log:
// 6 Jun 01
// WEKEMPF Initial version.
// 30 May 02 WEKEMPF
// Added interface to set specific cleanup handlers.
// Removed TLS slot limits from most implementations.
// 22 Mar 04 GlassfordM for WEKEMPF
// Fixed: thread_specific_ptr::reset() doesn't check error returned
// by tss::set(); tss::set() now throws if it fails.
// Fixed: calling thread_specific_ptr::reset() or
// thread_specific_ptr::release() causes double-delete: once on
// reset()/release() and once on ~thread_specific_ptr().

View File

@@ -56,6 +56,12 @@ namespace boost
long const current_thread_id=win32::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
{
return timed_lock(get_system_time()+timeout);
}
long get_active_count()
{
return mutex.get_active_count();

View File

@@ -59,8 +59,7 @@ namespace boost
void lock()
{
bool const success=timed_lock(::boost::detail::get_system_time_sentinel());
BOOST_ASSERT(success);
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
}
bool timed_lock(::boost::system_time const& wait_until)
{
@@ -105,6 +104,12 @@ namespace boost
return true;
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
{
return timed_lock(get_system_time()+timeout);
}
long get_active_count()
{
return ::boost::detail::interlocked_read_acquire(&active_count);

View File

@@ -13,6 +13,7 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include "interlocked_read.hpp"
#include <boost/thread/xtime.hpp>
namespace boost
{
@@ -79,8 +80,7 @@ namespace boost
{
if(entry.semaphore)
{
unsigned long const close_result=detail::win32::CloseHandle(entry.semaphore);
BOOST_ASSERT(close_result);
BOOST_VERIFY(detail::win32::CloseHandle(entry.semaphore));
entry.semaphore=0;
}
entry.notified=false;
@@ -111,54 +111,65 @@ namespace boost
};
template<typename lock_type>
void start_wait_loop_first_time(relocker<lock_type>& locker,
detail::win32::handle_manager& local_wake_sem)
{
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;
}
}
template<typename lock_type>
void start_wait_loop(relocker<lock_type>& locker,
detail::win32::handle_manager& local_wake_sem,
detail::win32::handle_manager& sem)
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
detail::interlocked_write_release(&total_count,total_count+1);
if(!local_wake_sem)
{
start_wait_loop_first_time(locker,local_wake_sem);
}
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);
}
protected:
template<typename lock_type>
bool do_wait(lock_type& lock,::boost::system_time const& wait_until)
bool do_wait(lock_type& lock,timeout 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)
{
start_wait_loop(locker,local_wake_sem,sem);
if(!this_thread::interruptible_wait(sem,wait_until))
{
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);
}
if(!this_thread::interruptible_wait(sem,::boost::detail::get_milliseconds_until(wait_until)))
{
break;
return false;
}
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
@@ -168,6 +179,17 @@ namespace boost
}
return woken;
}
template<typename lock_type,typename predicate_type>
bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!do_wait(m, wait_until))
return pred();
}
return true;
}
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
@@ -239,7 +261,7 @@ namespace boost
public:
void wait(unique_lock<mutex>& m)
{
do_wait(m,::boost::detail::get_system_time_sentinel());
do_wait(m,detail::timeout::sentinel());
}
template<typename predicate_type>
@@ -254,15 +276,30 @@ namespace boost
return do_wait(m,wait_until);
}
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
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;
return do_wait(m,wait_until,pred);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return do_wait(m,wait_duration.total_milliseconds(),pred);
}
};
@@ -273,7 +310,7 @@ namespace boost
template<typename lock_type>
void wait(lock_type& m)
{
do_wait(m,::boost::detail::get_system_time_sentinel());
do_wait(m,detail::timeout::sentinel());
}
template<typename lock_type,typename predicate_type>
@@ -288,15 +325,34 @@ namespace boost
return do_wait(m,wait_until);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
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;
return do_wait(m,wait_until,pred);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
{
return do_wait(m,wait_duration.total_milliseconds(),pred);
}
};

View File

@@ -40,13 +40,11 @@ namespace boost
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);
BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite));
}
~win32_mutex_scoped_lock()
{
bool const success=win32::ReleaseMutex(mutex_handle)!=0;
BOOST_ASSERT(success);
BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0);
}
};
@@ -96,9 +94,9 @@ namespace boost
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);
return win32::CreateMutexW(0, 0, mutex_name);
#else
return win32::CreateMutexA(NULL, 0, mutex_name);
return win32::CreateMutexA(0, 0, mutex_name);
#endif
}

View File

@@ -48,23 +48,21 @@ namespace boost
}
state_data state;
void* semaphores[2];
void* &unlock_sem;
void* &exclusive_sem;
void* upgrade_sem;
detail::win32::handle semaphores[2];
detail::win32::handle &unlock_sem;
detail::win32::handle &exclusive_sem;
detail::win32::handle 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);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0);
}
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);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
@@ -112,8 +110,7 @@ namespace boost
void lock_shared()
{
bool const success=timed_lock_shared(::boost::detail::get_system_time_sentinel());
BOOST_ASSERT(success);
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
}
bool timed_lock_shared(boost::system_time const& wait_until)
@@ -218,8 +215,7 @@ namespace boost
{
if(old_state.upgrade)
{
bool const success=detail::win32::ReleaseSemaphore(upgrade_sem,1,NULL)!=0;
BOOST_ASSERT(success);
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
}
else
{
@@ -235,8 +231,7 @@ namespace boost
void lock()
{
bool const success=timed_lock(::boost::detail::get_system_time_sentinel());
BOOST_ASSERT(success);
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
}
bool timed_lock(boost::system_time const& wait_until)
@@ -364,8 +359,7 @@ namespace boost
return;
}
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite);
BOOST_ASSERT(res==0);
BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
}
}
@@ -421,8 +415,7 @@ namespace boost
{
if(!last_reader)
{
unsigned long const res=detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite);
BOOST_ASSERT(res==0);
BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
}
break;
}

View File

@@ -15,9 +15,11 @@
#include "thread_primitives.hpp"
#include "thread_heap_alloc.hpp"
#include <boost/utility.hpp>
#include <boost/assert.hpp>
#include <list>
#include <algorithm>
#include <boost/ref.hpp>
#include <boost/cstdint.hpp>
namespace boost
{
@@ -27,6 +29,7 @@ namespace boost
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base
{
@@ -34,13 +37,14 @@ namespace boost
detail::win32::handle_manager thread_handle;
detail::win32::handle_manager interruption_handle;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interruption_enabled;
unsigned id;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
thread_exit_callbacks(0),
thread_exit_callbacks(0),tss_data(0),
interruption_enabled(true),
id(0)
{}
@@ -60,8 +64,92 @@ namespace boost
}
}
void interrupt()
{
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
}
virtual void run()=0;
};
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct timeout
{
unsigned long start;
uintmax_t milliseconds;
bool relative;
boost::system_time abs_time;
static unsigned long const max_non_infinite_wait=0xfffffffe;
timeout(uintmax_t milliseconds_):
start(win32::GetTickCount()),
milliseconds(milliseconds_),
relative(true),
abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
{}
struct remaining_time
{
bool more;
unsigned long milliseconds;
remaining_time(uintmax_t remaining):
more(remaining>max_non_infinite_wait),
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
{}
};
remaining_time remaining_milliseconds() const
{
if(is_sentinel())
{
return remaining_time(win32::infinite);
}
else if(relative)
{
unsigned long const now=win32::GetTickCount();
unsigned long const elapsed=now-start;
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
}
else
{
system_time const now=get_system_time();
if(abs_time<=now)
{
return remaining_time(0);
}
return remaining_time((abs_time-now).total_milliseconds()+1);
}
}
bool is_sentinel() const
{
return milliseconds==~uintmax_t(0);
}
static timeout sentinel()
{
return timeout(sentinel_type());
}
private:
struct sentinel_type
{};
explicit timeout(sentinel_type):
start(0),milliseconds(~uintmax_t(0)),relative(true)
{}
};
}
class BOOST_THREAD_DECL thread
@@ -81,7 +169,7 @@ namespace boost
thread_data(F f_):
f(f_)
{}
thread_data(boost::move_t<F> f_):
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
@@ -92,15 +180,15 @@ namespace boost
};
mutable boost::mutex thread_info_mutex;
boost::intrusive_ptr<detail::thread_data_base> thread_info;
detail::thread_data_ptr thread_info;
static unsigned __stdcall thread_start_function(void* param);
void start_thread();
explicit thread(boost::intrusive_ptr<detail::thread_data_base> data);
explicit thread(detail::thread_data_ptr data);
boost::intrusive_ptr<detail::thread_data_base> get_thread_info() const;
detail::thread_data_ptr get_thread_info() const;
public:
thread();
~thread();
@@ -112,16 +200,16 @@ namespace boost
start_thread();
}
template <class F>
explicit thread(boost::move_t<F> f):
thread(detail::thread_move_t<F> f):
thread_info(detail::heap_new<thread_data<F> >(f))
{
start_thread();
}
thread(boost::move_t<thread> x);
thread& operator=(boost::move_t<thread> x);
operator boost::move_t<thread>();
boost::move_t<thread> move();
thread(detail::thread_move_t<thread> x);
thread& operator=(detail::thread_move_t<thread> x);
operator detail::thread_move_t<thread>();
detail::thread_move_t<thread> move();
void swap(thread& x);
@@ -153,14 +241,20 @@ namespace boost
static void sleep(const system_time& xt);
// extensions
class interruption_handle;
interruption_handle get_interruption_handle() const;
void interrupt();
bool interruption_requested() const;
static thread self();
};
inline detail::thread_move_t<thread> move(thread& x)
{
return x.move();
}
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
{
return x;
}
template<typename F>
struct thread::thread_data<boost::reference_wrapper<F> >:
detail::thread_data_base
@@ -203,7 +297,7 @@ namespace boost
thread::id BOOST_THREAD_DECL get_id();
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds);
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline bool interruptible_wait(unsigned long milliseconds)
{
return interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
@@ -212,7 +306,6 @@ namespace boost
void BOOST_THREAD_DECL interruption_point();
bool BOOST_THREAD_DECL interruption_enabled();
bool BOOST_THREAD_DECL interruption_requested();
thread::interruption_handle BOOST_THREAD_DECL get_interruption_handle();
void BOOST_THREAD_DECL yield();
template<typename TimeDuration>
@@ -225,54 +318,70 @@ namespace boost
class thread::id
{
private:
unsigned thread_id;
detail::thread_data_ptr thread_data;
id(unsigned thread_id_):
thread_id(thread_id_)
id(detail::thread_data_ptr thread_data_):
thread_data(thread_data_)
{}
friend class thread;
friend id this_thread::get_id();
public:
id():
thread_id(0)
thread_data(0)
{}
bool operator==(const id& y) const
{
return thread_id==y.thread_id;
return thread_data==y.thread_data;
}
bool operator!=(const id& y) const
{
return thread_id!=y.thread_id;
return thread_data!=y.thread_data;
}
bool operator<(const id& y) const
{
return thread_id<y.thread_id;
return thread_data<y.thread_data;
}
bool operator>(const id& y) const
{
return thread_id>y.thread_id;
return y.thread_data<thread_data;
}
bool operator<=(const id& y) const
{
return thread_id<=y.thread_id;
return !(y.thread_data<thread_data);
}
bool operator>=(const id& y) const
{
return thread_id>=y.thread_id;
return !(thread_data<y.thread_data);
}
template<class charT, class traits>
friend std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
{
return os<<x.thread_id;
if(x.thread_data)
{
return os<<x.thread_data;
}
else
{
return os<<"{Not-any-thread}";
}
}
void interrupt()
{
if(thread_data)
{
thread_data->interrupt();
}
}
};
inline bool thread::operator==(const thread& other) const
@@ -284,56 +393,6 @@ namespace boost
{
return get_id()!=other.get_id();
}
class thread::interruption_handle
{
private:
boost::detail::win32::handle_manager handle;
friend class thread;
friend interruption_handle this_thread::get_interruption_handle();
interruption_handle(detail::win32::handle h_):
handle(h_)
{}
public:
interruption_handle(interruption_handle const& other):
handle(other.handle.duplicate())
{}
interruption_handle():
handle(0)
{}
void swap(interruption_handle& other)
{
handle.swap(other.handle);
}
interruption_handle& operator=(interruption_handle const& other)
{
interruption_handle temp(other);
swap(temp);
return *this;
}
void reset()
{
handle=0;
}
void interrupt()
{
if(handle)
{
detail::win32::SetEvent(handle);
}
}
typedef void(interruption_handle::*bool_type)();
operator bool_type() const
{
return handle?&interruption_handle::interrupt:0;
}
};
namespace detail
{
@@ -427,6 +486,18 @@ namespace boost
}
}
void interrupt_all()
{
boost::lock_guard<mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->interrupt();
}
}
int size() const
{
boost::lock_guard<mutex> guard(m);

View File

@@ -6,6 +6,8 @@
#define THREAD_HEAP_ALLOC_HPP
#include <new>
#include "thread_primitives.hpp"
#include <stdexcept>
#include <boost/assert.hpp>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
@@ -51,57 +53,116 @@ namespace boost
{
namespace detail
{
inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
{
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
if(!heap_memory)
{
throw std::bad_alloc();
}
return heap_memory;
}
inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
{
BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
}
template<typename T>
T* heap_new()
{
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
T* const data=new (heap_memory) T();
return data;
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T();
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1>
T* heap_new(A1 a1)
{
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
T* const data=new (heap_memory) T(a1);
return data;
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2>
T* heap_new(A1 a1,A2 a2)
{
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
T* const data=new (heap_memory) T(a1,a2);
return data;
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3>
T* heap_new(A1 a1,A2 a2,A3 a3)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2,a3);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2,a3,a4);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T>
void heap_delete(T* data)
{
data->~T();
detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,data);
free_raw_heap_memory(data);
}
template<typename T>
struct do_delete
struct do_heap_delete
{
T* data;
do_delete(T* data_):
data(data_)
{}
void operator()() const
void operator()(T* data) const
{
detail::heap_delete(data);
}
};
template<typename T>
do_delete<T> make_heap_deleter(T* data)
{
return do_delete<T>(data);
}
}
}

View File

@@ -53,6 +53,7 @@ namespace boost
using ::SleepEx;
using ::Sleep;
using ::QueueUserAPC;
using ::GetTickCount;
}
}
}
@@ -120,6 +121,8 @@ namespace boost
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) unsigned long __stdcall GetTickCount();
# ifndef UNDER_CE
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
@@ -178,9 +181,9 @@ namespace boost
inline handle create_anonymous_semaphore(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL);
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
#else
handle const res=CreateSemaphoreW(NULL,initial_count,max_count,NULL);
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
#endif
if(!res)
{
@@ -204,8 +207,7 @@ namespace boost
inline void release_semaphore(handle semaphore,long count)
{
bool const success=ReleaseSemaphore(semaphore,count,0)!=0;
BOOST_ASSERT(success);
BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
}
class handle_manager
@@ -219,8 +221,7 @@ namespace boost
{
if(handle_to_manage && handle_to_manage!=invalid_handle_value)
{
unsigned long const result=CloseHandle(handle_to_manage);
BOOST_ASSERT(result);
BOOST_VERIFY(CloseHandle(handle_to_manage));
}
}

View File

@@ -0,0 +1,103 @@
#ifndef BOOST_THREAD_WIN32_TSS_HPP
#define BOOST_THREAD_WIN32_TSS_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/shared_ptr.hpp>
#include "thread_heap_alloc.hpp"
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(data);
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
{}
explicit thread_specific_ptr(void (*func_)(T*)):
cleanup(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>())
{}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,0,0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#endif

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 William E. Kempf.
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<html>

51
src/pthread/once.cpp Executable file
View File

@@ -0,0 +1,51 @@
// 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)
#define __STDC_CONSTANT_MACROS
#include <boost/thread/once.hpp>
#include <boost/assert.hpp>
#include <pthread.h>
#include <stdlib.h>
namespace boost
{
namespace detail
{
BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
namespace
{
pthread_key_t epoch_tss_key;
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
extern "C" void delete_epoch_tss_data(void* data)
{
free(data);
}
extern "C" void create_epoch_tss_key()
{
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
}
}
boost::uintmax_t& get_once_per_thread_epoch()
{
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
void* data=pthread_getspecific(epoch_tss_key);
if(!data)
{
data=malloc(sizeof(boost::uintmax_t));
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
*static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
}
return *static_cast<boost::uintmax_t*>(data);
}
}
}

View File

@@ -12,6 +12,15 @@
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#ifdef __linux__
#include <sys/sysinfo.h>
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/types.h>
#include <sys/sysctl.h>
#elif defined(__sun)
#include <unistd.h>
#endif
#include "timeconv.inl"
@@ -23,6 +32,24 @@ namespace boost
{
boost::detail::thread_exit_function_base* func;
thread_exit_callback_node* next;
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
thread_exit_callback_node* next_):
func(func_),next(next_)
{}
};
struct tss_data_node
{
void const* key;
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
void* value;
tss_data_node* next;
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
tss_data_node* next_):
key(key_),func(func_),value(value_),next(next_)
{}
};
namespace
@@ -37,17 +64,31 @@ namespace boost
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
if(thread_info)
{
while(thread_info->thread_exit_callbacks)
while(thread_info->tss_data || thread_info->thread_exit_callbacks)
{
boost::detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
thread_info->thread_exit_callbacks=current_node->next;
if(current_node->func)
while(thread_info->thread_exit_callbacks)
{
(*current_node->func)();
delete current_node->func;
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
thread_info->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
(*current_node->func)();
delete current_node->func;
}
delete current_node;
}
while(thread_info->tss_data)
{
detail::tss_data_node* const current_node=thread_info->tss_data;
thread_info->tss_data=current_node->next;
if(current_node->func)
{
(*current_node->func)(current_node->value);
}
delete current_node;
}
delete current_node;
}
thread_info->self.reset();
}
}
}
@@ -55,8 +96,7 @@ namespace boost
void create_current_thread_tls_key()
{
int const res=pthread_key_create(&current_thread_tls_key,NULL);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
}
}
@@ -69,8 +109,7 @@ namespace boost
void set_current_thread_data(detail::thread_data_base* new_data)
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
int const res=pthread_setspecific(current_thread_tls_key,new_data);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
}
}
@@ -102,8 +141,39 @@ namespace boost
thread_info->done_condition.notify_all();
return 0;
}
}
struct externally_launched_thread:
detail::thread_data_base
{
externally_launched_thread()
{
interrupt_enabled=false;
}
void run()
{}
};
detail::thread_data_base* make_external_thread_data()
{
detail::thread_data_base* const me(new externally_launched_thread());
me->self.reset(me);
set_current_thread_data(me);
return me;
}
detail::thread_data_base* get_or_make_current_thread_data()
{
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
if(!current_thread_data)
{
current_thread_data=make_external_thread_data();
}
return current_thread_data;
}
}
@@ -126,6 +196,37 @@ namespace boost
detach();
}
thread::thread(detail::thread_move_t<thread> x)
{
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info.reset();
}
thread& thread::operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator detail::thread_move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> thread::move()
{
detail::thread_move_t<thread> x(*this);
return x;
}
void thread::swap(thread& x)
{
thread_info.swap(x.thread_info);
}
bool thread::operator==(const thread& other) const
{
return get_id()==other.get_id();
@@ -136,7 +237,7 @@ namespace boost
return !operator==(other);
}
boost::shared_ptr<detail::thread_data_base> thread::get_thread_info() const
detail::thread_data_ptr thread::get_thread_info() const
{
lock_guard<mutex> l(thread_info_mutex);
return thread_info;
@@ -144,7 +245,7 @@ namespace boost
void thread::join()
{
boost::shared_ptr<detail::thread_data_base> const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
bool do_join=false;
@@ -172,8 +273,7 @@ namespace boost
if(do_join)
{
void* result=0;
int const res=pthread_join(local_thread_info->thread_handle,&result);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
lock_guard<mutex> lock(local_thread_info->data_mutex);
local_thread_info->joined=true;
local_thread_info->done_condition.notify_all();
@@ -189,7 +289,7 @@ namespace boost
bool thread::timed_join(system_time const& wait_until)
{
boost::shared_ptr<detail::thread_data_base> const local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
bool do_join=false;
@@ -220,8 +320,7 @@ namespace boost
if(do_join)
{
void* result=0;
int const res=pthread_join(local_thread_info->thread_handle,&result);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
lock_guard<mutex> lock(local_thread_info->data_mutex);
local_thread_info->joined=true;
local_thread_info->done_condition.notify_all();
@@ -244,7 +343,7 @@ namespace boost
void thread::detach()
{
boost::shared_ptr<detail::thread_data_base> local_thread_info;
detail::thread_data_ptr local_thread_info;
{
lock_guard<mutex> l1(thread_info_mutex);
thread_info.swap(local_thread_info);
@@ -255,8 +354,7 @@ namespace boost
lock_guard<mutex> lock(local_thread_info->data_mutex);
if(!local_thread_info->join_started)
{
int const res=pthread_detach(local_thread_info->thread_handle);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
local_thread_info->join_started=true;
local_thread_info->joined=true;
}
@@ -281,9 +379,7 @@ namespace boost
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
timespec ts;
to_timespec_duration(xt, ts);
int res = 0;
res = pthread_delay_np(&ts);
BOOST_ASSERT(res == 0);
BOOST_VERIFY(!pthread_delay_np(&ts));
# elif defined(BOOST_HAS_NANOSLEEP)
timespec ts;
to_timespec_duration(xt, ts);
@@ -308,13 +404,9 @@ namespace boost
void thread::yield()
{
# if defined(BOOST_HAS_SCHED_YIELD)
int res = 0;
res = sched_yield();
BOOST_ASSERT(res == 0);
BOOST_VERIFY(!sched_yield());
# elif defined(BOOST_HAS_PTHREAD_YIELD)
int res = 0;
res = pthread_yield();
BOOST_ASSERT(res == 0);
BOOST_VERIFY(!pthread_yield());
# else
xtime xt;
xtime_get(&xt, TIME_UTC);
@@ -324,15 +416,28 @@ namespace boost
unsigned thread::hardware_concurrency()
{
return 1;
#if defined(PTW32_VERSION) || defined(__hpux)
return pthread_num_processors_np();
#elif defined(__linux__)
return get_nprocs();
#elif defined(__APPLE__) || defined(__FreeBSD__)
int count;
size_t size=sizeof(count);
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
#elif defined(__sun)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#else
return 0;
#endif
}
thread::id thread::get_id() const
{
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
return id(local_thread_info->thread_handle);
return id(local_thread_info);
}
else
{
@@ -342,22 +447,21 @@ namespace boost
void thread::interrupt()
{
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
local_thread_info->interrupt_requested=true;
if(local_thread_info->current_cond)
{
int const res=pthread_cond_broadcast(local_thread_info->current_cond);
BOOST_ASSERT(!res);
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
}
}
}
bool thread::interruption_requested() const
{
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
@@ -372,6 +476,12 @@ namespace boost
namespace this_thread
{
thread::id get_id()
{
boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr());
}
void interruption_point()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
@@ -440,6 +550,63 @@ namespace boost
}
}
namespace detail
{
void add_thread_exit_function(thread_exit_function_base* func)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
thread_exit_callback_node* const new_node=
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}
tss_data_node* find_tss_data(void const* key)
{
detail::thread_data_base* const current_thread_data(get_current_thread_data());
if(current_thread_data)
{
detail::tss_data_node* current_node=current_thread_data->tss_data;
while(current_node)
{
if(current_node->key==key)
{
return current_node;
}
current_node=current_node->next;
}
}
return NULL;
}
void* get_tss_data(void const* key)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
return current_node->value;
}
return NULL;
}
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func)
{
(*current_node->func)(current_node->value);
}
current_node->func=func;
current_node->value=tss_data;
}
else
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data);
current_thread_data->tss_data=new_node;
}
}
}
thread_group::thread_group()
{
}
@@ -503,6 +670,19 @@ namespace boost
}
}
void thread_group::interrupt_all()
{
boost::lock_guard<mutex> guard(m_mutex);
for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
it!=end;
++it)
{
(*it)->interrupt();
}
}
int thread_group::size() const
{
return m_threads.size();

View File

@@ -1,192 +0,0 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/tss.hpp>
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
#include <boost/thread/once.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/exceptions.hpp>
#include <vector>
#include <string>
#include <stdexcept>
#include <cassert>
#if defined(BOOST_HAS_WINTHREADS)
# include <windows.h>
# include <boost/thread/detail/tss_hooks.hpp>
#endif
namespace {
typedef std::vector<void*> tss_slots;
typedef std::vector<boost::function1<void, void*>*> tss_data_cleanup_handlers_type;
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;
pthread_key_t tss_data_native_key;
int tss_data_use = 0;
void tss_data_inc_use(boost::mutex::scoped_lock& lk)
{
++tss_data_use;
}
void tss_data_dec_use(boost::mutex::scoped_lock& lk)
{
if (0 == --tss_data_use)
{
tss_data_cleanup_handlers_type::size_type i;
for (i = 0; i < tss_data_cleanup_handlers->size(); ++i)
{
delete (*tss_data_cleanup_handlers)[i];
}
delete tss_data_cleanup_handlers;
tss_data_cleanup_handlers = 0;
lk.unlock();
delete tss_data_mutex;
tss_data_mutex = 0;
pthread_key_delete(tss_data_native_key);
}
}
extern "C" void cleanup_slots(void* p)
{
tss_slots* slots = static_cast<tss_slots*>(p);
boost::mutex::scoped_lock lock(*tss_data_mutex);
for (tss_slots::size_type i = 0; i < slots->size(); ++i)
{
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
(*slots)[i] = 0;
}
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<boost::mutex> temp_mutex(new boost::mutex);
if (temp_mutex.get() == 0)
throw boost::thread_resource_error();
int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
if (res != 0)
return;
// The life time of cleanup handlers and mutex is beeing
// managed by a reference counting technique.
// This avoids a memory leak by releasing the global data
// after last use only, since the execution order of cleanup
// handlers is unspecified on any platform with regards to
// C++ destructor ordering rules.
tss_data_cleanup_handlers = temp.release();
tss_data_mutex = temp_mutex.release();
}
tss_slots* get_slots(bool alloc)
{
tss_slots* slots = 0;
slots = static_cast<tss_slots*>(
pthread_getspecific(tss_data_native_key));
if (slots == 0 && alloc)
{
std::auto_ptr<tss_slots> temp(new tss_slots);
if (pthread_setspecific(tss_data_native_key, temp.get()) != 0)
return 0;
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_inc_use(lock);
}
slots = temp.release();
}
return slots;
}
} // namespace
namespace boost {
namespace detail {
void tss::init(boost::function1<void, void*>* pcleanup)
{
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);
try
{
tss_data_cleanup_handlers->push_back(pcleanup);
m_slot = tss_data_cleanup_handlers->size() - 1;
tss_data_inc_use(lock);
}
catch (...)
{
throw thread_resource_error();
}
}
tss::~tss()
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_dec_use(lock);
}
void* tss::get() const
{
tss_slots* slots = get_slots(false);
if (!slots)
return 0;
if (m_slot >= slots->size())
return 0;
return (*slots)[m_slot];
}
void tss::set(void* value)
{
tss_slots* slots = get_slots(true);
if (!slots)
throw boost::thread_resource_error();
if (m_slot >= slots->size())
{
try
{
slots->resize(m_slot + 1);
}
catch (...)
{
throw boost::thread_resource_error();
}
}
(*slots)[m_slot] = value;
}
void tss::cleanup(void* value)
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
(*(*tss_data_cleanup_handlers)[m_slot])(value);
}
} // namespace detail
} // namespace boost
#endif //BOOST_THREAD_NO_TSS_CLEANUP

View File

@@ -6,7 +6,7 @@
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST)) && (!defined(_MSC_VER) || defined(UNDER_CE))
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
/*
This file is a "null" implementation of tss cleanup; it's

View File

@@ -4,6 +4,9 @@
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
#define _WIN32_WINNT 0x400
#define WINVER 0x400
#include <boost/thread/thread.hpp>
#include <algorithm>
#include <windows.h>
@@ -12,34 +15,15 @@
#endif
#include <stdio.h>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#include <boost/assert.hpp>
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
namespace boost
{
namespace
{
#if defined(_MSC_VER) && !defined(UNDER_CE)
__declspec(thread) detail::thread_data_base* current_thread_data=0;
detail::thread_data_base* get_current_thread_data()
{
return current_thread_data;
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
current_thread_data=new_data;
}
#elif defined(__BORLANDC__)
detail::thread_data_base* __thread current_thread_data=0;
detail::thread_data_base* get_current_thread_data()
{
return current_thread_data;
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
current_thread_data=new_data;
}
#else
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
DWORD current_thread_tls_key=0;
@@ -58,10 +42,8 @@ namespace boost
void set_current_thread_data(detail::thread_data_base* new_data)
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
BOOL const res=TlsSetValue(current_thread_tls_key,new_data);
BOOST_ASSERT(res);
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
}
#endif
#ifdef BOOST_NO_THREADEX
// Windows CE doesn't define _beginthreadex
@@ -85,11 +67,11 @@ namespace boost
typedef void* uintptr_t;
inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
void* arglist, unsigned initflag, unsigned* thrdaddr)
void* arglist, unsigned initflag, unsigned* thrdaddr)
{
DWORD threadID;
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
new ThreadProxyData(start_address,arglist),initflag,&threadID);
new ThreadProxyData(start_address,arglist),initflag,&threadID);
if (hthread!=0)
*thrdaddr=threadID;
return reinterpret_cast<uintptr_t const>(hthread);
@@ -131,26 +113,53 @@ namespace boost
{}
};
struct tss_data_node
{
void const* key;
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
void* value;
tss_data_node* next;
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
tss_data_node* next_):
key(key_),func(func_),value(value_),next(next_)
{}
};
}
namespace
{
void run_thread_exit_callbacks()
{
boost::intrusive_ptr<detail::thread_data_base> current_thread_data(get_current_thread_data(),false);
detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
if(current_thread_data)
{
while(current_thread_data->thread_exit_callbacks)
while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
{
detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
current_thread_data->thread_exit_callbacks=current_node->next;
if(current_node->func)
while(current_thread_data->thread_exit_callbacks)
{
(*current_node->func)();
boost::detail::heap_delete(current_node->func);
detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
current_thread_data->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
(*current_node->func)();
boost::detail::heap_delete(current_node->func);
}
boost::detail::heap_delete(current_node);
}
while(current_thread_data->tss_data)
{
detail::tss_data_node* const current_node=current_thread_data->tss_data;
current_thread_data->tss_data=current_node->next;
if(current_node->func)
{
(*current_node->func)(current_node->value);
}
boost::detail::heap_delete(current_node);
}
boost::detail::heap_delete(current_node);
}
}
set_current_thread_data(0);
}
@@ -192,7 +201,7 @@ namespace boost
ResumeThread(thread_info->thread_handle);
}
thread::thread(boost::intrusive_ptr<detail::thread_data_base> data):
thread::thread(detail::thread_data_ptr data):
thread_info(data)
{}
@@ -205,53 +214,58 @@ namespace boost
{
++count;
interruption_enabled=false;
thread_handle=detail::win32::duplicate_handle(detail::win32::GetCurrentThread());
}
void run()
{}
};
}
thread thread::self()
{
if(!get_current_thread_data())
void make_external_thread_data()
{
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
set_current_thread_data(me);
}
return thread(boost::intrusive_ptr<detail::thread_data_base>(get_current_thread_data()));
detail::thread_data_base* get_or_make_current_thread_data()
{
detail::thread_data_base* current_thread_data(get_current_thread_data());
if(!current_thread_data)
{
make_external_thread_data();
current_thread_data=get_current_thread_data();
}
return current_thread_data;
}
}
thread::~thread()
{
detach();
}
thread::thread(boost::move_t<thread> x)
thread::thread(detail::thread_move_t<thread> x)
{
{
boost::mutex::scoped_lock l(x->thread_info_mutex);
thread_info=x->thread_info;
}
x->release_handle();
lock_guard<mutex> lock(x->thread_info_mutex);
thread_info=x->thread_info;
x->thread_info=0;
}
thread& thread::operator=(boost::move_t<thread> x)
thread& thread::operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator boost::move_t<thread>()
thread::operator detail::thread_move_t<thread>()
{
return move();
}
boost::move_t<thread> thread::move()
detail::thread_move_t<thread> thread::move()
{
boost::move_t<thread> x(*this);
detail::thread_move_t<thread> x(*this);
return x;
}
@@ -262,16 +276,9 @@ namespace boost
thread::id thread::get_id() const
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?thread::id(local_thread_info->id):thread::id();
return thread::id(get_thread_info());
}
thread::interruption_handle thread::get_interruption_handle() const
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?thread::interruption_handle(local_thread_info->interruption_handle.duplicate()):thread::interruption_handle();
}
bool thread::joinable() const
{
return get_thread_info();
@@ -279,17 +286,17 @@ namespace boost
void thread::join()
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=get_thread_info();
if(local_thread_info)
{
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::win32::infinite);
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
release_handle();
}
}
bool thread::timed_join(boost::system_time const& wait_until)
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=get_thread_info();
if(local_thread_info)
{
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
@@ -308,22 +315,22 @@ namespace boost
void thread::release_handle()
{
boost::mutex::scoped_lock l1(thread_info_mutex);
lock_guard<mutex> l1(thread_info_mutex);
thread_info=0;
}
void thread::interrupt()
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=get_thread_info();
if(local_thread_info)
{
detail::win32::SetEvent(local_thread_info->interruption_handle);
local_thread_info->interrupt();
}
}
bool thread::interruption_requested() const
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=get_thread_info();
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
}
@@ -336,11 +343,11 @@ namespace boost
thread::native_handle_type thread::native_handle()
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
detail::thread_data_ptr local_thread_info=get_thread_info();
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
}
boost::intrusive_ptr<detail::thread_data_base> thread::get_thread_info() const
detail::thread_data_ptr thread::get_thread_info() const
{
boost::mutex::scoped_lock l(thread_info_mutex);
return thread_info;
@@ -348,18 +355,57 @@ namespace boost
namespace this_thread
{
thread::interruption_handle get_interruption_handle()
namespace
{
return get_current_thread_data()?thread::interruption_handle(get_current_thread_data()->interruption_handle.duplicate()):thread::interruption_handle();
}
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
{
LARGE_INTEGER due_time={0};
if(target_time.relative)
{
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
bool interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds)
if(remaining_milliseconds>0)
{
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
}
}
else
{
SYSTEMTIME target_system_time={0};
target_system_time.wYear=target_time.abs_time.date().year();
target_system_time.wMonth=target_time.abs_time.date().month();
target_system_time.wDay=target_time.abs_time.date().day();
target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
{
due_time.QuadPart=0;
}
else
{
long const hundred_nanoseconds_in_one_second=10000000;
due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
}
}
return due_time;
}
}
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
{
detail::win32::handle handles[2]={0};
detail::win32::handle handles[3]={0};
unsigned handle_count=0;
unsigned wait_handle_index=~0U;
unsigned interruption_index=~0U;
unsigned timeout_index=~0U;
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
{
wait_handle_index=handle_count;
handles[handle_count++]=handle_to_wait_for;
}
if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
@@ -367,30 +413,85 @@ namespace boost
interruption_index=handle_count;
handles[handle_count++]=get_current_thread_data()->interruption_handle;
}
detail::win32::handle_manager timer_handle;
#ifndef UNDER_CE
unsigned const min_timer_wait_period=20;
if(!target_time.is_sentinel())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
if(time_left.milliseconds > min_timer_wait_period)
{
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
LARGE_INTEGER due_time=get_due_time(target_time);
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
if(set_time_succeeded)
{
timeout_index=handle_count;
handles[handle_count++]=timer_handle;
}
}
}
else if(!target_time.relative)
{
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
target_time=detail::timeout(time_left.milliseconds);
}
}
#endif
if(handle_count)
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
do
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,milliseconds);
if((handle_to_wait_for!=detail::win32::invalid_handle_value) && !notified_index)
if(!using_timer)
{
return true;
time_left=target_time.remaining_milliseconds();
}
else if(notified_index==interruption_index)
if(handle_count)
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
{
return true;
}
else if(notified_index==interruption_index)
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
else if(notified_index==timeout_index)
{
return false;
}
}
}
else
{
detail::win32::Sleep(time_left.milliseconds);
}
if(target_time.relative)
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
}
}
else
{
detail::win32::Sleep(milliseconds);
}
while(time_left.more);
return false;
}
thread::id get_id()
{
return thread::id(detail::win32::GetCurrentThreadId());
return thread::id(get_or_make_current_thread_data());
}
void interruption_point()
@@ -451,49 +552,78 @@ namespace boost
}
}
namespace
{
void NTAPI thread_exit_func_callback(HINSTANCE, DWORD, PVOID);
typedef void (NTAPI* tls_callback)(HINSTANCE, DWORD, PVOID);
#ifdef _MSC_VER
extern "C"
{
extern DWORD _tls_used; //the tls directory (located in .rdata segment)
extern tls_callback __xl_a[], __xl_z[]; //tls initializers */
}
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(push, old_seg)
#endif
#pragma data_seg(".CRT$XLB")
tls_callback p_thread_callback = thread_exit_func_callback;
#pragma data_seg()
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(pop, old_seg)
#endif
#endif
void NTAPI thread_exit_func_callback(HINSTANCE h, DWORD dwReason, PVOID pv)
{
if((dwReason==DLL_THREAD_DETACH) || (dwReason==DLL_PROCESS_DETACH))
{
run_thread_exit_callbacks();
}
}
}
namespace detail
{
void add_thread_exit_function(thread_exit_function_base* func)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
thread_exit_callback_node* const new_node=
heap_new<thread_exit_callback_node>(func,
get_current_thread_data()->thread_exit_callbacks);
get_current_thread_data()->thread_exit_callbacks=new_node;
current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}
tss_data_node* find_tss_data(void const* key)
{
detail::thread_data_base* const current_thread_data(get_current_thread_data());
if(current_thread_data)
{
detail::tss_data_node* current_node=current_thread_data->tss_data;
while(current_node)
{
if(current_node->key==key)
{
return current_node;
}
current_node=current_node->next;
}
}
return NULL;
}
void* get_tss_data(void const* key)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
return current_node->value;
}
return NULL;
}
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func.get())
{
(*current_node->func)(current_node->value);
}
current_node->func=func;
current_node->value=tss_data;
}
else
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
current_thread_data->tss_data=new_node;
}
}
}
}
extern "C" BOOST_THREAD_DECL void on_process_enter()
{}
extern "C" BOOST_THREAD_DECL void on_thread_enter()
{}
extern "C" BOOST_THREAD_DECL void on_process_exit()
{}
extern "C" BOOST_THREAD_DECL void on_thread_exit()
{
boost::run_thread_exit_callbacks();
}

View File

@@ -1,211 +0,0 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// Copyright (C) 2007 Anthony Williams
// Copyright (C) 2007 David Deakins
//
// 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/tss.hpp>
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
#include <boost/thread/once.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/exceptions.hpp>
#include <vector>
#include <string>
#include <stdexcept>
#include <cassert>
#include <windows.h>
#include <boost/thread/detail/tss_hooks.hpp>
#if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES)
# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
#endif
namespace {
typedef std::vector<void*> tss_slots;
typedef std::vector<boost::function1<void, void*>*> tss_data_cleanup_handlers_type;
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;
DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
int tss_data_use = 0;
void tss_data_inc_use(boost::mutex::scoped_lock& lk)
{
++tss_data_use;
}
void tss_data_dec_use(boost::mutex::scoped_lock& lk)
{
if (0 == --tss_data_use)
{
tss_data_cleanup_handlers_type::size_type i;
for (i = 0; i < tss_data_cleanup_handlers->size(); ++i)
{
delete (*tss_data_cleanup_handlers)[i];
}
delete tss_data_cleanup_handlers;
tss_data_cleanup_handlers = 0;
lk.unlock();
delete tss_data_mutex;
tss_data_mutex = 0;
TlsFree(tss_data_native_key);
tss_data_native_key=TLS_OUT_OF_INDEXES;
}
}
extern "C" void cleanup_slots(void* p)
{
tss_slots* slots = static_cast<tss_slots*>(p);
boost::mutex::scoped_lock lock(*tss_data_mutex);
for (tss_slots::size_type i = 0; i < slots->size(); ++i)
{
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
(*slots)[i] = 0;
}
TlsSetValue(tss_data_native_key,0);
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<boost::mutex> temp_mutex(new boost::mutex);
if (temp_mutex.get() == 0)
throw boost::thread_resource_error();
//Force the cleanup implementation library to be linked in
tss_cleanup_implemented();
//Allocate tls slot
tss_data_native_key = TlsAlloc();
if (tss_data_native_key == TLS_OUT_OF_INDEXES)
return;
// The life time of cleanup handlers and mutex is beeing
// managed by a reference counting technique.
// This avoids a memory leak by releasing the global data
// after last use only, since the execution order of cleanup
// handlers is unspecified on any platform with regards to
// C++ destructor ordering rules.
tss_data_cleanup_handlers = temp.release();
tss_data_mutex = temp_mutex.release();
}
tss_slots* get_slots(bool alloc);
void __cdecl tss_thread_exit()
{
tss_slots* slots = get_slots(false);
if (slots)
cleanup_slots(slots);
}
tss_slots* get_slots(bool alloc)
{
tss_slots* slots = 0;
slots = static_cast<tss_slots*>(
TlsGetValue(tss_data_native_key));
if (slots == 0 && alloc)
{
std::auto_ptr<tss_slots> temp(new tss_slots);
if (at_thread_exit(&tss_thread_exit) == -1)
return 0;
if (!TlsSetValue(tss_data_native_key, temp.get()))
return 0;
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_inc_use(lock);
}
slots = temp.release();
}
return slots;
}
} // namespace
namespace boost {
namespace detail {
void tss::init(boost::function1<void, void*>* pcleanup)
{
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);
try
{
tss_data_cleanup_handlers->push_back(pcleanup);
m_slot = tss_data_cleanup_handlers->size() - 1;
tss_data_inc_use(lock);
}
catch (...)
{
throw thread_resource_error();
}
}
tss::~tss()
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
tss_data_dec_use(lock);
}
void* tss::get() const
{
tss_slots* slots = get_slots(false);
if (!slots)
return 0;
if (m_slot >= slots->size())
return 0;
return (*slots)[m_slot];
}
void tss::set(void* value)
{
tss_slots* slots = get_slots(true);
if (!slots)
throw boost::thread_resource_error();
if (m_slot >= slots->size())
{
try
{
slots->resize(m_slot + 1);
}
catch (...)
{
throw boost::thread_resource_error();
}
}
(*slots)[m_slot] = value;
}
void tss::cleanup(void* value)
{
boost::mutex::scoped_lock lock(*tss_data_mutex);
(*(*tss_data_cleanup_handlers)[m_slot])(value);
}
} // namespace detail
} // namespace boost
#endif //BOOST_THREAD_NO_TSS_CLEANUP

View File

@@ -1,218 +0,0 @@
// Copyright (C) 2004 Michael Glassford
// Copyright (C) 2006 Roland Schwarz
// Copyright (C) 2007 Anthony Williams
// Copyright (C) 2007 David Deakins
// 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)
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS)
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/assert.hpp>
// #include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <list>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
# if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES)
# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
# endif
namespace
{
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;
}
/*
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.
*/
extern "C" BOOST_THREAD_DECL int at_thread_exit(
thread_exit_handler exit_handler
)
{
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
{
exit_handlers->push_front(exit_handler);
}
catch (...)
{
return -1;
}
//Like the atexit() function, a result of zero
//indicates success.
return 0;
}
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);
BOOST_ASSERT(attached_thread_count == 0);
}
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
{
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
BOOST_ASSERT(attached_thread_count == 0);
//Free the tls slot if one was allocated.
if (tls_key != invalid_tls_key)
{
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())
{
if (thread_exit_handler exit_handler = *exit_handlers->begin())
(*exit_handler)();
exit_handlers->pop_front();
}
delete exit_handlers;
exit_handlers = 0;
}
}
#endif //defined(BOOST_HAS_WINTHREADS)

View File

@@ -1,4 +1,6 @@
// $Id$
// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
// (C) Copyright 2007 Roland Schwarz
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
// Use, modification and distribution are subject to the
@@ -7,7 +9,75 @@
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_THREAD_BUILD_LIB) && defined(_MSC_VER) && !defined(UNDER_CE)
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#if defined(__MINGW32__) && !defined(_WIN64)
#include <boost/thread/detail/tss_hooks.hpp>
#include <windows.h>
#include <cstdlib>
extern "C" void tss_cleanup_implemented(void) {}
namespace {
void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
{
on_thread_exit();
break;
}
}
}
void on_after_ctors(void)
{
on_process_enter();
}
void on_before_dtors(void)
{
on_thread_exit();
}
void on_after_dtors(void)
{
on_process_exit();
}
}
extern "C" {
void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors;
void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors;
void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors;
ULONG __tls_index__ = 0;
char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
char __tls_start__ __attribute__((section(".tls"))) = 0;
PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
}
extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
{
(DWORD) &__tls_start__,
(DWORD) &__tls_end__,
(DWORD) &__tls_index__,
(DWORD) (&__crt_xl_start__+1),
(DWORD) 0,
(DWORD) 0
};
#elif defined(_MSC_VER) && !defined(UNDER_CE)
#include <boost/thread/detail/tss_hooks.hpp>
@@ -50,6 +120,16 @@
//The .CRT$Xxx information is taken from Codeguru:
//http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
#if (_MSC_VER >= 1400)
#pragma section(".CRT$XIU",long,read)
#pragma section(".CRT$XCU",long,read)
#pragma section(".CRT$XTU",long,read)
#pragma section(".CRT$XLC",long,read)
static __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
static __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
static __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
static __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
#else
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(push, old_seg)
#endif
@@ -74,7 +154,6 @@
#pragma data_seg(".CRT$XLB")
_TLSCB p_thread_callback = on_tls_callback;
#pragma data_seg()
//Callback for termination.
#pragma data_seg(".CRT$XTU")
@@ -83,6 +162,7 @@
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(pop, old_seg)
#endif
#endif
PVAPI on_tls_prepare(void)
{
@@ -177,5 +257,6 @@
longer needed and can be removed.
*/
}
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)

View File

@@ -1,2 +0,0 @@
bin
*.pdb

View File

@@ -1,4 +1,5 @@
# (C) Copyright William E. Kempf 2001.
# (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)
#
@@ -34,13 +35,21 @@ rule thread-run ( sources )
{
test-suite "threads"
: [ thread-run test_thread.cpp ]
[ thread-run test_thread_id.cpp ]
[ thread-run test_hardware_concurrency.cpp ]
[ thread-run test_thread_move.cpp ]
[ thread-run test_move_function.cpp ]
[ thread-run test_mutex.cpp ]
[ thread-run test_condition_notify_one.cpp ]
[ thread-run test_condition_timed_wait_times_out.cpp ]
[ thread-run test_condition_notify_all.cpp ]
[ thread-run test_condition.cpp ]
[ thread-run test_tss.cpp ]
[ thread-run test_once.cpp ]
[ thread-run test_xtime.cpp ]
[ thread-run test_barrier.cpp ]
[ thread-run test_shared_mutex.cpp ]
[ thread-run test_shared_mutex_part_2.cpp ]
[ thread-run test_lock_concept.cpp ]
;
}

View File

@@ -0,0 +1,95 @@
#ifndef CONDITION_TEST_COMMON_HPP
#define CONDITION_TEST_COMMON_HPP
// 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)
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread_time.hpp>
unsigned const timeout_seconds=5;
struct wait_for_flag
{
boost::mutex mutex;
boost::condition_variable cond_var;
bool flag;
unsigned woken;
wait_for_flag():
flag(false),woken(0)
{}
struct check_flag
{
bool const& flag;
check_flag(bool const& flag_):
flag(flag_)
{}
bool operator()() const
{
return flag;
}
};
void wait_without_predicate()
{
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
cond_var.wait(lock);
}
++woken;
}
void wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
cond_var.wait(lock,check_flag(flag));
if(flag)
{
++woken;
}
}
void timed_wait_without_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
if(!cond_var.timed_wait(lock,timeout))
{
return;
}
}
++woken;
}
void timed_wait_with_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
{
++woken;
}
}
void relative_timed_wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
{
++woken;
}
}
};
#endif

View File

@@ -0,0 +1,62 @@
#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP
#define SHARED_MUTEX_LOCKING_THREAD_HPP
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/shared_mutex.hpp>
template<typename lock_type>
class locking_thread
{
boost::shared_mutex& rw_mutex;
unsigned& unblocked_count;
boost::condition_variable& unblocked_condition;
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::condition_variable& unblocked_condition_,
boost::mutex& finish_mutex_,
unsigned& simultaneous_running_count_,
unsigned& max_simultaneous_running_):
rw_mutex(rw_mutex_),
unblocked_count(unblocked_count_),
unblocked_condition(unblocked_condition_),
simultaneous_running_count(simultaneous_running_count_),
max_simultaneous_running(max_simultaneous_running_),
unblocked_count_mutex(unblocked_count_mutex_),
finish_mutex(finish_mutex_)
{}
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;
unblocked_condition.notify_one();
++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;
}
}
};
#endif

View File

@@ -10,6 +10,7 @@
#include <boost/thread/barrier.hpp>
#include <boost/test/unit_test.hpp>
#include <vector>
namespace {
@@ -38,12 +39,20 @@ void test_barrier()
boost::thread_group g;
global_parameter = 0;
for (int i = 0; i < N_THREADS; ++i)
g.create_thread(&barrier_thread);
g.join_all();
BOOST_CHECK(global_parameter == 5);
try
{
for (int i = 0; i < N_THREADS; ++i)
g.create_thread(&barrier_thread);
g.join_all();
}
catch(...)
{
g.interrupt_all();
g.join_all();
throw;
}
BOOST_CHECK_EQUAL(global_parameter,5);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

View File

@@ -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)
@@ -19,7 +20,7 @@ struct condition_test_data
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition condition;
boost::condition_variable condition;
int notified;
int awoken;
};
@@ -82,56 +83,15 @@ void condition_test_waits(condition_test_data* data)
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_notify_one()
{
condition_test_data data;
boost::thread thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_one();
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 1);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one, 100, execution_monitor::use_mutex);
}
void do_test_condition_notify_all()
{
const int NUMTHREADS = 5;
boost::thread_group threads;
condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_all();
}
threads.join_all();
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
}
void test_condition_notify_all()
{
// We should have already tested notify_one here, so
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_notify_all, 100);
// Test predicate timed_wait with relative timeout
cond_predicate pred_rel(data->notified, 5);
BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred_rel());
BOOST_CHECK_EQUAL(data->notified, 5);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_waits()
@@ -175,10 +135,19 @@ void do_test_condition_waits()
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 4);
boost::thread::sleep(delay(1));
data.notified++;
data.condition.notify_one();
while (data.awoken != 5)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 5);
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 4);
BOOST_CHECK_EQUAL(data.awoken, 5);
}
void test_condition_waits()
@@ -206,14 +175,11 @@ void test_condition_wait_is_a_interruption_point()
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
test->add(BOOST_TEST_CASE(&test_condition_waits));
test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));

View File

@@ -0,0 +1,180 @@
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
unsigned const number_of_test_threads=5;
void do_test_condition_notify_all_wakes_from_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void test_condition_notify_all()
{
timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
return test;
}

View File

@@ -0,0 +1,113 @@
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
void do_test_condition_notify_one_wakes_from_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
return test;
}

View File

@@ -0,0 +1,89 @@
// 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)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include "util.inl"
bool fake_predicate()
{
return false;
}
unsigned const timeout_seconds=5;
unsigned const timeout_grace=1;
boost::posix_time::milliseconds const timeout_resolution(100);
void do_test_timed_wait_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
while(cond.timed_wait(lock,timeout));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_relative_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
bool const res=cond.timed_wait(lock,delay,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void test_timed_wait_times_out()
{
timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
return test;
}

View File

@@ -0,0 +1,21 @@
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
void test_hardware_concurrency_is_non_zero()
{
BOOST_CHECK(boost::thread::hardware_concurrency()!=0);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
return test;
}

View File

@@ -0,0 +1,54 @@
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
void do_nothing()
{}
void test_thread_move_from_lvalue_on_construction()
{
boost::thread src(do_nothing);
boost::thread::id src_id=src.get_id();
boost::thread dest(boost::move(src));
boost::thread::id dest_id=dest.get_id();
BOOST_CHECK(src_id==dest_id);
BOOST_CHECK(src.get_id()==boost::thread::id());
dest.join();
}
void test_thread_move_from_rvalue_on_construction()
{
boost::thread x(boost::move(boost::thread(do_nothing)));
BOOST_CHECK(x.get_id()!=boost::thread::id());
x.join();
}
void test_unique_lock_move_from_lvalue_on_construction()
{
boost::mutex m;
boost::unique_lock<boost::mutex> l(m);
BOOST_CHECK(l.owns_lock());
BOOST_CHECK(l.mutex()==&m);
boost::unique_lock<boost::mutex> l2(boost::move(l));
BOOST_CHECK(!l.owns_lock());
BOOST_CHECK(!l.mutex());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l2.mutex()==&m);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction));
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
return test;
}

View File

@@ -102,6 +102,11 @@ struct test_timedlock
typedef M mutex_type;
typedef typename M::scoped_timed_lock timed_lock_type;
static bool fake_predicate()
{
return false;
}
void operator()()
{
mutex_type mutex;
@@ -123,14 +128,17 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100);
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(in_range(xt));
boost::system_time now=boost::get_system_time();
boost::posix_time::milliseconds const timeout_resolution(20);
BOOST_CHECK((timeout-timeout_resolution)<now);
// Test the lock, unlock and timedlock methods.
lock.unlock();
@@ -142,6 +150,17 @@ struct test_timedlock
boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
BOOST_CHECK(lock.timed_lock(target));
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
BOOST_CHECK(mutex.timed_lock(boost::posix_time::milliseconds(100)));
mutex.unlock();
BOOST_CHECK(lock.timed_lock(boost::posix_time::milliseconds(100)));
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
}
};

View File

@@ -19,6 +19,7 @@ void initialize_variable()
++var_to_init;
}
void call_once_thread()
{
unsigned const loop_count=100;
@@ -40,12 +41,22 @@ void test_call_once()
{
unsigned const num_threads=20;
boost::thread_group group;
for(unsigned i=0;i<num_threads;++i)
try
{
group.create_thread(&call_once_thread);
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_thread);
}
group.join_all();
}
group.join_all();
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
BOOST_CHECK_EQUAL(var_to_init,1);
}
@@ -88,11 +99,21 @@ void test_call_once_arbitrary_functor()
unsigned const num_threads=20;
boost::thread_group group;
for(unsigned i=0;i<num_threads;++i)
try
{
group.create_thread(&call_once_with_functor);
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_functor);
}
group.join_all();
}
group.join_all();
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
}
@@ -137,11 +158,21 @@ void test_call_once_retried_on_exception()
unsigned const num_threads=20;
boost::thread_group group;
for(unsigned i=0;i<num_threads;++i)
try
{
group.create_thread(&call_once_with_exception);
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_exception);
}
group.join_all();
}
group.join_all();
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3u);
BOOST_CHECK_EQUAL(exception_counter,2u);
}

View File

@@ -5,12 +5,9 @@
#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"
#include <iostream>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include "shared_mutex_locking_thread.hpp"
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
@@ -18,61 +15,6 @@
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_),
simultaneous_running_count(simultaneous_running_count_),
max_simultaneous_running(max_simultaneous_running_),
unblocked_count_mutex(unblocked_count_mutex_),
finish_mutex(finish_mutex_)
{}
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;
@@ -84,21 +26,38 @@ void test_multiple_readers()
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
for(unsigned i=0;i<number_of_threads;++i)
try
{
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));
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,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<number_of_threads)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
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);
}
@@ -114,21 +73,32 @@ void test_only_one_writer_permitted()
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
for(unsigned i=0;i<number_of_threads;++i)
try
{
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));
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,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(2));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
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,1u);
@@ -143,19 +113,38 @@ void test_reader_blocks_writer()
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
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);
try
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<1)
{
unblocked_condition.wait(lk);
}
}
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,unblocked_condition,
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();
finish_lock.unlock();
pool.join_all();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
@@ -171,25 +160,44 @@ void test_unlocking_writer_unblocks_all_readers()
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
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)
try
{
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);
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,unblocked_condition,
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();
write_lock.unlock();
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
finish_lock.unlock();
pool.join_all();
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
}
@@ -204,6 +212,7 @@ void test_unlocking_last_reader_only_unblocks_one_writer()
unsigned simultaneous_running_writers=0;
unsigned max_simultaneous_writers=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_reading_mutex;
boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex);
boost::mutex finish_writing_mutex;
@@ -212,235 +221,55 @@ void test_unlocking_last_reader_only_unblocks_one_writer()
unsigned const reader_count=100;
unsigned const writer_count=100;
for(unsigned i=0;i<reader_count;++i)
try
{
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<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
}
boost::thread::sleep(delay(1));
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,unblocked_condition,
finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
}
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_reading_lock.unlock();
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_writing_lock.unlock();
pool.join_all();
}
for(unsigned i=0;i<writer_count;++i)
catch(...)
{
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));
pool.interrupt_all();
pool.join_all();
throw;
}
boost::thread::sleep(delay(2));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_reading_lock.unlock();
boost::thread::sleep(delay(2));
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,1u);
}
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,1u);
}
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,1u);
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,1u);
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,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(2000);
bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK(in_range(boost::get_xtime(timeout),1));
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 =
@@ -451,12 +280,6 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
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;
}

View File

@@ -0,0 +1,271 @@
// (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/xtime.hpp>
#include "util.inl"
#include "shared_mutex_locking_thread.hpp"
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
boost::mutex::scoped_lock lock(mutex_name); \
BOOST_CHECK_EQUAL(value,expected_value); \
}
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::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
{
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,unblocked_condition,
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();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
}
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::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=100;
try
{
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,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
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::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
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,1u);
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,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(2000);
boost::posix_time::milliseconds const timeout_resolution(20);
bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK((timeout-timeout_resolution)<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_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;
}

149
test/test_thread_id.cpp Normal file
View File

@@ -0,0 +1,149 @@
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
void do_nothing()
{}
void test_thread_id_for_default_constructed_thread_is_default_constructed_id()
{
boost::thread t;
BOOST_CHECK(t.get_id()==boost::thread::id());
}
void test_thread_id_for_running_thread_is_not_default_constructed_id()
{
boost::thread t(do_nothing);
BOOST_CHECK(t.get_id()!=boost::thread::id());
t.join();
}
void test_different_threads_have_different_ids()
{
boost::thread t(do_nothing);
boost::thread t2(do_nothing);
BOOST_CHECK(t.get_id()!=t2.get_id());
t.join();
t2.join();
}
void test_thread_ids_have_a_total_order()
{
boost::thread t(do_nothing);
boost::thread t2(do_nothing);
boost::thread t3(do_nothing);
BOOST_CHECK(t.get_id()!=t2.get_id());
BOOST_CHECK(t.get_id()!=t3.get_id());
BOOST_CHECK(t2.get_id()!=t3.get_id());
BOOST_CHECK((t.get_id()<t2.get_id()) != (t2.get_id()<t.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) != (t3.get_id()<t.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) != (t3.get_id()<t2.get_id()));
BOOST_CHECK((t.get_id()>t2.get_id()) != (t2.get_id()>t.get_id()));
BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>t.get_id()));
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>t3.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>t2.get_id()));
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>t3.get_id()));
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>=t.get_id()));
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>=t2.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>=t.get_id()));
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>=t3.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>=t2.get_id()));
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>=t3.get_id()));
BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id()));
BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id()));
BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id()));
BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id()));
if((t.get_id()<t2.get_id()) && (t2.get_id()<t3.get_id()))
{
BOOST_CHECK(t.get_id()<t3.get_id());
}
else if((t.get_id()<t3.get_id()) && (t3.get_id()<t2.get_id()))
{
BOOST_CHECK(t.get_id()<t2.get_id());
}
else if((t2.get_id()<t3.get_id()) && (t3.get_id()<t.get_id()))
{
BOOST_CHECK(t2.get_id()<t.get_id());
}
else if((t2.get_id()<t.get_id()) && (t.get_id()<t3.get_id()))
{
BOOST_CHECK(t2.get_id()<t3.get_id());
}
else if((t3.get_id()<t.get_id()) && (t.get_id()<t2.get_id()))
{
BOOST_CHECK(t3.get_id()<t2.get_id());
}
else if((t3.get_id()<t2.get_id()) && (t2.get_id()<t.get_id()))
{
BOOST_CHECK(t3.get_id()<t.get_id());
}
else
{
BOOST_CHECK(false);
}
boost::thread::id default_id;
BOOST_CHECK(default_id < t.get_id());
BOOST_CHECK(default_id < t2.get_id());
BOOST_CHECK(default_id < t3.get_id());
BOOST_CHECK(default_id <= t.get_id());
BOOST_CHECK(default_id <= t2.get_id());
BOOST_CHECK(default_id <= t3.get_id());
BOOST_CHECK(!(default_id > t.get_id()));
BOOST_CHECK(!(default_id > t2.get_id()));
BOOST_CHECK(!(default_id > t3.get_id()));
BOOST_CHECK(!(default_id >= t.get_id()));
BOOST_CHECK(!(default_id >= t2.get_id()));
BOOST_CHECK(!(default_id >= t3.get_id()));
t.join();
t2.join();
t3.join();
}
void get_thread_id(boost::thread::id* id)
{
*id=boost::this_thread::get_id();
}
void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
{
boost::thread::id id;
boost::thread t(boost::bind(get_thread_id,&id));
boost::thread::id t_id=t.get_id();
t.join();
BOOST_CHECK(id==t_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id));
test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id));
test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids));
test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order));
test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id));
return test;
}

37
test/test_thread_move.cpp Normal file
View File

@@ -0,0 +1,37 @@
// 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)
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
void do_nothing()
{}
void test_move_on_construction()
{
boost::thread x=boost::thread(do_nothing);
x.join();
}
boost::thread make_thread()
{
return boost::thread(do_nothing);
}
void test_move_from_function_return()
{
boost::thread x=make_thread();
x.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: thread move test suite");
test->add(BOOST_TEST_CASE(test_move_on_construction));
test->add(BOOST_TEST_CASE(test_move_from_function_return));
return test;
}

View File

@@ -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)
@@ -62,7 +63,7 @@ void test_tss_thread()
}
}
#if defined(BOOST_HAS_WINTHREADS)
#if defined(BOOST_THREAD_PLATFORM_WIN32)
typedef HANDLE native_thread_t;
DWORD WINAPI test_tss_thread_native(LPVOID lpParameter)
@@ -73,7 +74,7 @@ void test_tss_thread()
native_thread_t create_native_thread(void)
{
return CreateThread(
native_thread_t const res=CreateThread(
0, //security attributes (0 = not inheritable)
0, //stack size (0 = default)
&test_tss_thread_native, //function to execute
@@ -81,6 +82,8 @@ void test_tss_thread()
0, //creation flags (0 = run immediately)
0 //thread id (0 = thread id not returned)
);
BOOST_CHECK(res!=0);
return res;
}
void join_native_thread(native_thread_t thread)
@@ -91,6 +94,33 @@ void test_tss_thread()
res = CloseHandle(thread);
BOOST_CHECK(SUCCEEDED(res));
}
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
typedef pthread_t native_thread_t;
extern "C"
{
void* test_tss_thread_native(void* lpParameter)
{
test_tss_thread();
return 0;
}
}
native_thread_t create_native_thread()
{
native_thread_t thread_handle;
int const res = pthread_create(&thread_handle, 0, &test_tss_thread_native, 0);
BOOST_CHECK(!res);
return thread_handle;
}
void join_native_thread(native_thread_t thread)
{
void* result=0;
int const res=pthread_join(thread,&result);
BOOST_CHECK(!res);
}
#endif
void do_test_tss()
@@ -100,9 +130,19 @@ void do_test_tss()
const int NUMTHREADS=5;
boost::thread_group threads;
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_tss_thread);
threads.join_all();
try
{
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_tss_thread);
threads.join_all();
}
catch(...)
{
threads.interrupt_all();
threads.join_all();
throw;
}
std::cout
<< "tss_instances = " << tss_instances
@@ -113,44 +153,33 @@ void do_test_tss()
BOOST_CHECK_EQUAL(tss_instances, 0);
BOOST_CHECK_EQUAL(tss_total, 5);
#if defined(BOOST_HAS_WINTHREADS)
tss_instances = 0;
tss_total = 0;
tss_instances = 0;
tss_total = 0;
native_thread_t thread1 = create_native_thread();
BOOST_CHECK(thread1 != 0);
native_thread_t thread1 = create_native_thread();
native_thread_t thread2 = create_native_thread();
native_thread_t thread3 = create_native_thread();
native_thread_t thread4 = create_native_thread();
native_thread_t thread5 = create_native_thread();
native_thread_t thread2 = create_native_thread();
BOOST_CHECK(thread2 != 0);
join_native_thread(thread5);
join_native_thread(thread4);
join_native_thread(thread3);
join_native_thread(thread2);
join_native_thread(thread1);
native_thread_t thread3 = create_native_thread();
BOOST_CHECK(thread3 != 0);
std::cout
<< "tss_instances = " << tss_instances
<< "; tss_total = " << tss_total
<< "\n";
std::cout.flush();
native_thread_t thread4 = create_native_thread();
BOOST_CHECK(thread3 != 0);
native_thread_t thread5 = create_native_thread();
BOOST_CHECK(thread3 != 0);
join_native_thread(thread5);
join_native_thread(thread4);
join_native_thread(thread3);
join_native_thread(thread2);
join_native_thread(thread1);
std::cout
<< "tss_instances = " << tss_instances
<< "; tss_total = " << tss_total
<< "\n";
std::cout.flush();
// 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_EQUAL(tss_total, 5);
#endif
// 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_EQUAL(tss_total, 5);
}
void test_tss()

View File

@@ -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)
@@ -154,6 +155,26 @@ thread_binder<F, T> bind(const F& func, const T& param)
{
return thread_binder<F, T>(func, param);
}
template <typename R, typename T>
class thread_member_binder
{
public:
thread_member_binder(R (T::*func)(), T& param)
: func(func), param(param) { }
void operator()() const { (param.*func)(); }
private:
R (T::*func)();
T& param;
};
template <typename R, typename T>
thread_member_binder<R, T> bind(R (T::*func)(), T& param)
{
return thread_member_binder<R, T>(func, param);
}
} // namespace
#endif