2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-07 10:52:10 +00:00

Compare commits

..

38 Commits

Author SHA1 Message Date
Vladimir Prus
dd51f97e44 Create branch to keep WIP patch for modular build.
[SVN r85883]
2013-09-25 08:12:19 +00:00
Tim Blechmann
04e3d918fb thread: implement physical_concurrency
[SVN r85864]
2013-09-24 06:41:24 +00:00
Vicente J. Botet Escriba
0073516f0a Thread: added missing function wrapper.
[SVN r85863]
2013-09-24 05:35:11 +00:00
Vicente J. Botet Escriba
89de3dcf4f Thread: make it possible to use non default constructible types in sync_queue, but sync_bounded_queue requires it yet.
[SVN r85861]
2013-09-23 21:40:08 +00:00
Vicente J. Botet Escriba
47f40f991f Thread: added first thread_pool.
[SVN r85855]
2013-09-23 16:45:00 +00:00
Vicente J. Botet Escriba
8b351fe473 Thread: fix some move semantic issues on sync_queue and sync_bounded_queue and add tests.
[SVN r85854]
2013-09-23 16:44:26 +00:00
Vicente J. Botet Escriba
24f1e620e8 Thread: fix some move issues on sync_queue.
[SVN r85841]
2013-09-22 22:23:58 +00:00
Vicente J. Botet Escriba
ed6459ecd2 Thread: make code uniform heap_new/heap_delete pairwise.
[SVN r85840]
2013-09-22 22:22:08 +00:00
Vicente J. Botet Escriba
858816b2d2 Thread: add detail:: to access detail::win32::GetTickCount64().
[SVN r85772]
2013-09-18 10:58:46 +00:00
Vicente J. Botet Escriba
4bc70444a4 Thread: try to fix SIGSEGV on win32 issue #7666.
[SVN r85734]
2013-09-17 21:17:02 +00:00
Vicente J. Botet Escriba
fcc027369f Thread: try to fix win32 condition_variable issue #7461.
[SVN r85733]
2013-09-17 21:01:05 +00:00
Vicente J. Botet Escriba
5c78582794 Thread: refactor make_ready_at_thread_exit + inhibit at_thread_exit functions from external threads.
[SVN r85732]
2013-09-17 20:57:46 +00:00
Vicente J. Botet Escriba
7f479a1dec Thread: Added test for tickets.
[SVN r85729]
2013-09-17 19:32:03 +00:00
Vicente J. Botet Escriba
4f2a7b2256 Thread: make use of explicit noncopyable constructor to avoid compile error with Intel compiler.
[SVN r85728]
2013-09-17 19:25:18 +00:00
Vicente J. Botet Escriba
5c88e6ce61 Thread: patch for #8070 to make use of GetTickCount64 when available.
[SVN r85714]
2013-09-16 19:43:37 +00:00
Vicente J. Botet Escriba
650e374492 Thread: Added ostream_buffer.
[SVN r85709]
2013-09-16 17:24:30 +00:00
Vicente J. Botet Escriba
6319080ef2 Thread: add test for get_exception_ptr.
[SVN r85708]
2013-09-16 17:15:05 +00:00
Vicente J. Botet Escriba
3ac48bdd65 Thread: patch for #8070 to make use of GetTickCount64 when available.
[SVN r85701]
2013-09-16 16:55:21 +00:00
Vicente J. Botet Escriba
c3c8ada97d Thread: replace TABS.
[SVN r85677]
2013-09-15 16:13:47 +00:00
Vicente J. Botet Escriba
fd5dd0c2ed Thread: added future<>::get_exception_ptr().
[SVN r85644]
2013-09-10 19:40:14 +00:00
Vicente J. Botet Escriba
4a83aa58ed Thread: add workaround for non compliants compilers on scoped_thread constructor.
[SVN r85643]
2013-09-10 18:55:52 +00:00
Vicente J. Botet Escriba
7d96aa625c Thread: update doc with history.
[SVN r85623]
2013-09-09 17:37:54 +00:00
Vicente J. Botet Escriba
d57a4c6565 Thread: link with boost_atomic conditionaly.
[SVN r85616]
2013-09-08 22:20:48 +00:00
Vicente J. Botet Escriba
c67e39f126 Thread: protect condition_variable/_any wait_for and wait_until from malicious input.
[SVN r85592]
2013-09-07 12:11:44 +00:00
Vicente J. Botet Escriba
5a3c301582 Thread: protect condition_variable/_any wait_for and wait_until from malicious input.
[SVN r85591]
2013-09-07 12:11:18 +00:00
Vicente J. Botet Escriba
dc5a8a9c4e Thread: try to handle with not needed definition of uintptr_t #8817.
[SVN r85540]
2013-09-01 07:25:56 +00:00
Vicente J. Botet Escriba
1e49343ff4 Thread: try to handle with call_once intel issue #8943.
[SVN r85539]
2013-09-01 07:22:21 +00:00
Vicente J. Botet Escriba
93d1855e64 Thread: fix scoped_thread variadic constructor.
[SVN r85494]
2013-08-27 22:37:15 +00:00
Vicente J. Botet Escriba
a39dd7e8b3 Thread: avoid conflict with thread symbol.
[SVN r85493]
2013-08-27 22:35:21 +00:00
Vicente J. Botet Escriba
7e5cb92bab Thread: fix some typos in doc.
[SVN r85492]
2013-08-27 22:31:32 +00:00
Vicente J. Botet Escriba
62cf0f86f6 Thread: fix more typos in doc.
[SVN r85485]
2013-08-27 11:32:24 +00:00
Vicente J. Botet Escriba
c12e07754a Thread: link with boost_chrono and boost_atomic independently of the platform.
[SVN r85464]
2013-08-25 15:13:17 +00:00
Vicente J. Botet Escriba
cbc4266774 Thread: rename wait_until parameter to avoid shadow with member function.
[SVN r85463]
2013-08-25 15:09:12 +00:00
Vicente J. Botet Escriba
3a038d33e5 Thread: rename check by cgeck_counter to avoid conflict with macro.
[SVN r85462]
2013-08-25 15:08:08 +00:00
Vicente J. Botet Escriba
51ba4be998 Thread: fix type and add BOOST_THREAD_USE_ATOMIC macro doc.
[SVN r85432]
2013-08-22 22:11:48 +00:00
Vicente J. Botet Escriba
2d50af8481 Thread: Added synchronized_value operator() to synchronize around a function call.
[SVN r85306]
2013-08-11 20:33:47 +00:00
Vicente J. Botet Escriba
e438c98070 Thread: Add mutex() to upgrade_to_unique_lock (#8891).
[SVN r85195]
2013-08-03 07:47:18 +00:00
Vicente J. Botet Escriba
1e2a76de47 Thread: apply pathc for #8931.
[SVN r85194]
2013-08-03 07:44:15 +00:00
26 changed files with 1560 additions and 105 deletions

View File

@@ -10,45 +10,21 @@
[heading Version 4.2.0 - boost 1.55]
[*Know Bugs:]
* [@http://svn.boost.org/trac/boost/ticket/2442 #2442] Application statically linked with Boost.Thread crashes when Google Desktop is installed (Windows XP)
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
* [@http://svn.boost.org/trac/boost/ticket/6782 #6782] call_once uses incorrect barrier intrinsic on Visual Studio
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
* [@http://svn.boost.org/trac/boost/ticket/9307 #9307] future::fallback_to assert with ERRORRRRR boost: mutex lock failed in pthread_mutex_lock: Invalid argument
* [@http://svn.boost.org/trac/boost/ticket/9308 #9308] future::async fails with terminate called throwing an exception when called with a lambda - clang-darwin-asan11
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread trunk regression test] to see the current state.
[*Sever limitations:]
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
* on thread specific storage that prevent the library to be used with dynamic libraries,
* The experimental features of boost::future have some severe holes that make the program crash unexpectedly.
[*New Features:]
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Synchro: Update class barrier with a completion function.
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Synchro: Update class barrier with a completion function
* [@http://svn.boost.org/trac/boost/ticket/8615 #8615] Async: Replace make_future/make_shared_future by make_ready_future.
* [@http://svn.boost.org/trac/boost/ticket/8627 #8627] Async: Add future<>::unwrap and unwrapping constructor.
* [@http://svn.boost.org/trac/boost/ticket/8677 #8677] Async: Add future<>::get_or.
* [@http://svn.boost.org/trac/boost/ticket/8678 #8678] Async: Add future<>::fallback_to.
* [@http://svn.boost.org/trac/boost/ticket/8891 #8891] upgrade_to_unique_lock: missing mutex() function.
* [@http://svn.boost.org/trac/boost/ticket/8955 #8955] Request for more efficient way to get exception_ptr from future.
* [@http://svn.boost.org/trac/boost/ticket/8891 #8891] upgrade_to_unique_lock: missing mutex() function.
[*Fixed Bugs:]
* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0 Boost 1.55.0 closed viboes Bugs
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
* [@http://svn.boost.org/trac/boost/ticket/8768 #8768] win32 condition_variable::wait_until infinite wait in rare cases.
* [@http://svn.boost.org/trac/boost/ticket/8817 #8817] Boost Thread Windows CE _createthreadex handling breaks mingw w64.
* [@http://svn.boost.org/trac/boost/ticket/8943 #8943] Failed to compile code using boost::call_once with Intel C++ Composer XE 2013 on Windows.

View File

@@ -216,6 +216,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
void detach();
static unsigned hardware_concurrency() noexcept;
static unsigned physical_concurrency() noexcept;
typedef thread::native_handle_type native_handle_type;
native_handle_type native_handle();
@@ -458,6 +459,20 @@ any) to `*this`.
[endsect]
[section:physical_concurrency Static member function `physical_concurrency()`]
unsigned physical_concurrency() noexecpt;
[variablelist
[[Effects:] [Equivalent to return `thread::physical_concurrency()`.]]
]
[endsect]
[section:nativehandle Member function `native_handle()`]
typedef thread::native_handle_type native_handle_type;

View File

@@ -249,7 +249,7 @@
[section:sds Synchronized Data Structures]
[include synchronized_value.qbk]
[/include sync_queues_ref.qbk]
[include sync_queues_ref.qbk]
[/include sync_streams.qbk]
[endsect]

View File

@@ -470,6 +470,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
void detach();
static unsigned hardware_concurrency() noexcept;
static unsigned physical_concurrency() noexcept;
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
@@ -991,6 +992,21 @@ or 0 if this information is not available.]]
[endsect]
[section:physical_concurrency Static member function `physical_concurrency()`]
unsigned physical_concurrency() noexecpt;
[variablelist
[[Returns:] [The number of physical cores available on the current system. In contrast to `hardware_concurrency()` it does not return
the number of virtual cores, but it counts only physical cores.]]
[[Throws:] [Nothing]]
]
[endsect]
[section:nativehandle Member function `native_handle()`]
typedef platform-specific-type native_handle_type;

View File

@@ -0,0 +1,61 @@
// (C) Copyright 2012 Howard Hinnant
// (C) Copyright 2012 Vicente Botet
//
// 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)
// adapted from the example given by Howard Hinnant in
#define BOOST_THREAD_VERSION 4
#include <iostream>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/ostream_buffer.hpp>
void use_cerr()
{
using namespace boost;
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
int i = 0;
while (chrono::steady_clock::now() < tf)
{
ostream_buffer<std::ostream> mcerr(std::cerr);
mcerr.stream() << "logging data to cerr " << i++ << "\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
void use_cout()
{
using namespace boost;
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
int i = 0;
while (chrono::steady_clock::now() < tf)
{
ostream_buffer<std::ostream> mcout(std::cout);
mcout.stream() << "logging data to cout " << i++ << "\n";
this_thread::sleep_for(chrono::milliseconds(500));
}
}
int main()
{
using namespace boost;
scoped_thread<> t1(&use_cerr);
scoped_thread<> t2(&use_cout);
this_thread::sleep_for(chrono::seconds(2));
std::string nm = "he, he\n";
{
ostream_buffer<std::ostream> mcout(std::cout);
mcout.stream() << "Enter name: \n";
}
t1.join();
t2.join();
{
ostream_buffer<std::ostream> mcout(std::cout);
mcout.stream() << nm;
}
return 0;
}

147
example/thread_pool.cpp Normal file
View File

@@ -0,0 +1,147 @@
// Copyright (C) 2012-2013 Vicente Botet
//
// 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 BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/detail/log.hpp>
#include <boost/thread/thread_pool.hpp>
#include <boost/assert.hpp>
#include <string>
void p1()
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " P1" << BOOST_THREAD_END_LOG;
}
void p2()
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
}
void push(boost::container::deque<boost::detail::function_wrapper> &data_, BOOST_THREAD_RV_REF(boost::detail::function_wrapper) closure)
{
try
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
boost::detail::function_wrapper v;
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
//v = boost::move(closure);
//v = boost::forward<boost::detail::function_wrapper>(closure);
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
data_.push_back(boost::move(closure));
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
//data_.push_back(boost::forward<boost::detail::function_wrapper>(closure));
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
}
catch (...)
{
BOOST_THREAD_LOG
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
}
}
template <typename Closure>
void submit(boost::container::deque<boost::detail::function_wrapper> &data_, BOOST_THREAD_FWD_REF(Closure) closure)
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
//work w =boost::move(closure);
//work_queue.push(boost::move(w));
//push(data_, boost::detail::function_wrapper(boost::forward<Closure>(closure)));
boost::detail::function_wrapper v =boost::forward<Closure>(closure);
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
push(data_, boost::move(v));
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
}
int main()
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
#if 0
{
try
{
boost::detail::function_wrapper f(&p1);
boost::container::deque<boost::detail::function_wrapper> data_;
data_.push_back(boost::move(f));
data_.push_back(boost::detail::function_wrapper(&p1));
submit(data_, &p1);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
}
catch (...)
{
BOOST_THREAD_LOG
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
}
typedef boost::container::vector<boost::thread> thread_vector;
thread_vector threads;
}
#endif
#if 1
{
try
{
boost::thread_pool tp;
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
tp.submit(&p1);
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
#endif
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << "MAIN>" << BOOST_THREAD_END_LOG;
return 0;
}

View File

@@ -0,0 +1,94 @@
// Copyright (C) 2013 Vicente J. Botet Escriba
//
// 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)
//
// 2013/09 Vicente J. Botet Escriba
// Adapt to boost from CCIA C++11 implementation
// Make use of Boost.Move
#ifndef BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
#define BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
#include <boost/config.hpp>
#include <boost/thread/detail/memory.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
#include <memory>
#include <functional>
namespace boost
{
namespace detail
{
class function_wrapper
{
struct impl_base
{
virtual void call()=0;
virtual ~impl_base()
{
}
};
//typedef boost::interprocess::unique_ptr<impl_base, boost::default_delete<impl_base> > impl_base_type;
impl_base* impl;
template <typename F>
struct impl_type: impl_base
{
F f;
impl_type(F const &f_)
: f(f_)
{}
impl_type(BOOST_THREAD_RV_REF(F) f_)
: f(boost::move(f_))
{}
void call()
{
f();
}
};
public:
BOOST_THREAD_MOVABLE_ONLY(function_wrapper)
//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
template<typename F>
function_wrapper(F const& f):
impl(new impl_type<F>(f))
{}
//#endif
template<typename F>
function_wrapper(BOOST_THREAD_RV_REF(F) f):
impl(new impl_type<F>(boost::forward<F>(f)))
{}
function_wrapper(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT :
impl(other.impl)
{
other.impl = 0;
}
function_wrapper()
: impl(0)
{
}
~function_wrapper()
{
delete impl;
}
function_wrapper& operator=(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT
{
impl=other.impl;
other.impl=0;
return *this;
}
void operator()()
{ impl->call();}
};
}
}
#endif // header

View File

@@ -546,6 +546,7 @@ namespace boost
void detach();
static unsigned hardware_concurrency() BOOST_NOEXCEPT;
static unsigned physical_concurrency() BOOST_NOEXCEPT;
#define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
typedef detail::thread_data_base::native_handle_type native_handle_type;

View File

@@ -201,8 +201,12 @@ namespace boost
struct shared_state_base : enable_shared_from_this<shared_state_base>
{
typedef std::list<boost::condition_variable_any*> waiter_list;
// This type should be only included conditionally if interruptions are allowed, but is included to maintain the same layout.
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
typedef shared_ptr<shared_state_base> continuation_ptr_type;
#else
// This type shouldn't be included, but is included to maintain the same layout.
typedef shared_ptr<void> continuation_ptr_type;
#endif
boost::exception_ptr exception;
bool done;
@@ -213,7 +217,7 @@ namespace boost
boost::condition_variable waiters;
waiter_list external_waiters;
boost::function<void()> callback;
// This declaration should be only included conditionally if interruptions are allowed, but is included to maintain the same layout.
// This declaration should be only included conditionally, but is included to maintain the same layout.
bool thread_was_interrupted;
// This declaration should be only included conditionally, but is included to maintain the same layout.
continuation_ptr_type continuation_ptr;
@@ -817,12 +821,8 @@ namespace boost
struct future_async_shared_state_base: shared_state<Rp>
{
typedef shared_state<Rp> base_type;
protected:
boost::thread thr_;
void join()
{
if (thr_.joinable()) thr_.join();
}
public:
future_async_shared_state_base()
{
@@ -836,12 +836,12 @@ namespace boost
~future_async_shared_state_base()
{
join();
if (thr_.joinable()) thr_.join();
}
virtual void wait(bool rethrow)
{
join();
if (thr_.joinable()) thr_.join();
this->base_type::wait(rethrow);
}
};
@@ -959,11 +959,7 @@ namespace boost
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
try
{
Fp local_fuct=boost::move(func_);
relocker relock(lck);
Rp res = local_fuct();
relock.lock();
this->mark_finished_with_result_internal(boost::move(res), lck);
this->mark_finished_with_result_internal(func_(), lck);
}
catch (...)
{
@@ -1012,10 +1008,7 @@ namespace boost
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
try
{
Fp local_fuct=boost::move(func_);
relocker relock(lck);
local_fuct();
relock.lock();
func_();
this->mark_finished_with_result_internal(lck);
}
catch (...)
@@ -1556,7 +1549,7 @@ namespace boost
}
template <typename R2>
typename boost::disable_if< is_void<R2>, move_dest_type>::type
typename disable_if< is_void<R2>, move_dest_type>::type
get_or(BOOST_THREAD_RV_REF(R2) v)
{
if(!this->future_)
@@ -1577,7 +1570,7 @@ namespace boost
}
template <typename R2>
typename boost::disable_if< is_void<R2>, move_dest_type>::type
typename disable_if< is_void<R2>, move_dest_type>::type
get_or(R2 const& v) // EXTENSION
{
if(!this->future_)
@@ -1617,17 +1610,17 @@ namespace boost
then(launch policy, BOOST_THREAD_FWD_REF(F) func); // EXTENSION
template <typename R2>
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
fallback_to(BOOST_THREAD_RV_REF(R2) v); // EXTENSION
template <typename R2>
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
fallback_to(R2 const& v); // EXTENSION
#endif
//#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
// inline
// typename boost::enable_if<
// typename enable_if<
// is_future_type<value_type>,
// value_type
// //BOOST_THREAD_FUTURE<typename is_future_type<value_type>::type>
@@ -1898,7 +1891,7 @@ namespace boost
}
template <typename R2>
typename boost::disable_if< is_void<R2>, typename detail::shared_state<R>::shared_future_get_result_type>::type
typename disable_if< is_void<R2>, typename detail::shared_state<R>::shared_future_get_result_type>::type
get_or(BOOST_THREAD_RV_REF(R2) v) // EXTENSION
{
if(!this->future_)
@@ -1933,7 +1926,7 @@ namespace boost
#endif
//#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
// inline
// typename boost::enable_if_c<
// typename enable_if_c<
// is_future_type<value_type>::value,
// BOOST_THREAD_FUTURE<typename is_future_type<value_type>::type>
// >::type
@@ -3105,7 +3098,7 @@ namespace boost
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <class F>
explicit packaged_task(BOOST_THREAD_FWD_REF(F) f
, typename boost::disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
, typename disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
)
{
typedef typename remove_cv<typename remove_reference<F>::type>::type FR;
@@ -3126,7 +3119,7 @@ namespace boost
#else
template <class F>
explicit packaged_task(F const& f
, typename boost::disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
, typename disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0
)
{
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
@@ -3776,10 +3769,6 @@ namespace boost
that->mark_exceptional_finish();
}
}
~future_async_continuation_shared_state()
{
this->join();
}
};
template<typename F, typename Fp>
@@ -3821,10 +3810,6 @@ namespace boost
that->mark_exceptional_finish();
}
}
~future_async_continuation_shared_state()
{
this->join();
}
};
@@ -3855,12 +3840,7 @@ namespace boost
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
try
{
Fp local_fuct=boost::move(continuation);
F ftmp = boost::move(parent);
relocker relock(lck);
Rp res = local_fuct(boost::move(ftmp));
relock.lock();
this->mark_finished_with_result_internal(boost::move(res), lck);
this->mark_finished_with_result_internal(continuation(boost::move(parent)), lck);
}
catch (...)
{
@@ -3892,11 +3872,7 @@ namespace boost
virtual void execute(boost::unique_lock<boost::mutex>& lck) {
try
{
Fp local_fuct=boost::move(continuation);
F ftmp = boost::move(parent);
relocker relock(lck);
local_fuct(boost::move(ftmp));
relock.lock();
continuation(boost::move(parent));
this->mark_finished_with_result_internal(lck);
}
catch (...)
@@ -3969,6 +3945,7 @@ namespace boost
}
else
{
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
lock, boost::move(*this), boost::forward<F>(func)
)));
@@ -4001,6 +3978,7 @@ namespace boost
}
else
{
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>(
lock, boost::move(*this), boost::forward<F>(func)
);
@@ -4085,6 +4063,7 @@ namespace boost
}
else
{
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<shared_future<R>, future_type, F>(
lock, boost::move(*this), boost::forward<F>(func)
)));
@@ -4117,6 +4096,7 @@ namespace boost
}
else
{
//BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
return boost::detail::make_future_async_continuation_shared_state<shared_future<R>, future_type, F>(
lock, boost::move(*this), boost::forward<F>(func)
);
@@ -4161,7 +4141,7 @@ namespace boost
template <typename R>
template <typename R2>
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
BOOST_THREAD_FUTURE<R>::fallback_to(BOOST_THREAD_RV_REF(R2) v)
{
return then(detail::mfallbacker_to<R>(boost::move(v)));
@@ -4169,7 +4149,7 @@ namespace boost
template <typename R>
template <typename R2>
inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
inline typename disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type
BOOST_THREAD_FUTURE<R>::fallback_to(R2 const& v)
{
return then(detail::cfallbacker_to<R>(v));
@@ -4214,6 +4194,8 @@ namespace boost
make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f)
{
shared_ptr<future_unwrap_shared_state<F, Rp> >
//shared_ptr<basic_future<Rp> >
//typename boost::detail::basic_future<Rp>::future_ptr
h(new future_unwrap_shared_state<F, Rp>(boost::move(f)));
h->parent.future_->set_continuation_ptr(h, lock);
return BOOST_THREAD_FUTURE<Rp>(h);

View File

@@ -0,0 +1,35 @@
// (C) Copyright 2013 Vicente J. Botet Escriba
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_THREAD_OSTREAM_BUFFER_HPP
#define BOOST_THREAD_OSTREAM_BUFFER_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <sstream>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
template <typename OStream>
class ostream_buffer
{
public:
typedef std::basic_ostringstream<typename OStream::char_type, typename OStream::traits_type> stream_type;
ostream_buffer(OStream& os) : os_(os) {}
~ostream_buffer() { os_ << o_str_.str(); }
stream_type& stream() { return o_str_; }
private:
OStream& os_;
stream_type o_str_;
};
}
#include <boost/config/abi_suffix.hpp>
#endif // header

View File

@@ -261,11 +261,15 @@ namespace boost
}
#endif
static unsigned hardware_concurrency()BOOST_NOEXCEPT
static unsigned hardware_concurrency() BOOST_NOEXCEPT
{
return thread::hardware_concurrency();
}
static unsigned physical_concurrency() BOOST_NOEXCEPT
{
return thread::physical_concurrency();
}
};
/**

View File

@@ -31,7 +31,9 @@ namespace boost
struct no_block_tag{};
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
struct sync_queue_is_closed : std::exception {};
struct sync_queue_is_closed : std::exception
{
};
template <typename ValueType>
class sync_bounded_queue
@@ -155,6 +157,13 @@ namespace boost
out_ = inc(out_);
notify_not_full_if_needed(lk);
}
inline value_type pull(unique_lock<mutex>& lk)
{
value_type elem = boost::move(data_[out_]);
out_ = inc(out_);
notify_not_full_if_needed(lk);
return boost::move(elem);
}
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
{
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
@@ -408,9 +417,9 @@ namespace boost
{
try
{
value_type elem;
pull(elem);
return boost::move(elem);
unique_lock<mutex> lk(mtx_);
wait_until_not_empty(lk);
return pull(lk);
}
catch (...)
{
@@ -529,7 +538,7 @@ namespace boost
try
{
unique_lock<mutex> lk(mtx_);
return try_push(elem, lk);
return try_push(boost::move(elem), lk);
}
catch (...)
{
@@ -548,7 +557,7 @@ namespace boost
{
return false;
}
return try_push(elem, lk);
return try_push(boost::move(elem), lk);
}
catch (...)
{
@@ -563,7 +572,7 @@ namespace boost
try
{
unique_lock<mutex> lk(mtx_);
push_at(elem, wait_until_not_full(lk), lk);
push_at(boost::move(elem), wait_until_not_full(lk), lk);
}
catch (...)
{
@@ -575,7 +584,7 @@ namespace boost
template <typename ValueType>
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
{
sbq.push(boost::forward<ValueType>(elem));
sbq.push(boost::move(elem));
return sbq;
}

View File

@@ -52,10 +52,11 @@ namespace boost
inline void close();
inline void push(const value_type& x);
inline void push(BOOST_THREAD_RV_REF(value_type) x);
inline bool try_push(const value_type& x);
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
inline bool try_push(no_block_tag, const value_type& x);
inline void push(BOOST_THREAD_RV_REF(value_type) x);
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
// Observers/Modifiers
@@ -114,6 +115,12 @@ namespace boost
elem = boost::move(data_.front());
data_.pop_front();
}
inline value_type pull(unique_lock<mutex>& )
{
value_type e = boost::move(data_.front());
data_.pop_front();
return boost::move(e);
}
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& )
{
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_.front()));
@@ -129,7 +136,7 @@ namespace boost
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
{
data_.push(boost::move(elem));
data_.push_back(boost::move(elem));
notify_not_empty_if_needed(lk);
}
};
@@ -346,9 +353,9 @@ namespace boost
{
try
{
value_type elem;
pull(elem);
return boost::move(elem);
unique_lock<mutex> lk(mtx_);
wait_until_not_empty(lk);
return pull(lk);
}
catch (...)
{
@@ -431,7 +438,7 @@ namespace boost
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
{
throw_if_closed(lk);
push(boost::forward<ValueType>(elem), lk);
push(boost::move(elem), lk);
return true;
}
@@ -441,7 +448,7 @@ namespace boost
try
{
unique_lock<mutex> lk(mtx_);
return try_push(elem, lk);
return try_push(boost::move(elem), lk);
}
catch (...)
{
@@ -460,7 +467,7 @@ namespace boost
{
return false;
}
return try_push(elem, lk);
return try_push(boost::move(elem), lk);
}
catch (...)
{
@@ -476,7 +483,7 @@ namespace boost
{
unique_lock<mutex> lk(mtx_);
throw_if_closed(lk);
push(elem, lk);
push(boost::move(elem), lk);
}
catch (...)
{
@@ -488,7 +495,7 @@ namespace boost
template <typename ValueType>
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
{
sbq.push(boost::forward<ValueType>(elem));
sbq.push(boost::move(elem));
return sbq;
}

View File

@@ -0,0 +1,192 @@
// Copyright (C) 2013 Vicente J. Botet Escriba
//
// 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)
//
// 2013/09 Vicente J. Botet Escriba
// Adapt to boost from CCIA C++11 implementation
// first implementation of a simple pool thread using a vector of threads and a sync_queue.
#ifndef BOOST_THREAD_THREAD_POOL_HPP
#define BOOST_THREAD_THREAD_POOL_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/sync_queue.hpp>
#include <boost/thread/detail/function_wrapper.hpp>
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
#include <boost/function.hpp>
#else
#include <functional>
#endif
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
#include <boost/container/vector.hpp>
#else
#include <vector>
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class thread_pool
{
/// type-erasure to store the works to do
typedef detail::function_wrapper work;
/// the kind of stored threads are scoped threads to ensure that the threads are joined.
/// A move aware vector type
typedef scoped_thread<> thread_t;
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
typedef container::vector<thread_t> thread_vector;
#else
typedef std::vector<thread_t> thread_vector;
#endif
/// the thread safe work queue
sync_queue<work > work_queue;
/// A move aware vector
thread_vector threads;
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool try_executing_one()
{
work task;
try
{
if (work_queue.try_pull(task))
{
task();
return true;
}
return false;
}
catch (std::exception& ex)
{
return false;
}
catch (...)
{
return false;
}
}
/**
* Effects: schedule one task or yields
* Throws: whatever the current task constructor throws or the task() throws.
*/
void schedule_one_or_yield()
{
if ( ! try_executing_one())
{
this_thread::yield();
}
}
/**
* The main loop of the worker threads
*/
void worker_thread()
{
while (!is_closed())
{
schedule_one_or_yield();
}
}
public:
/// thread_pool is not copyable.
BOOST_THREAD_NO_COPYABLE(thread_pool)
/**
* Effects: creates a thread pool that runs closures on @c thread_count threads.
*/
thread_pool(unsigned const thread_count = thread::hardware_concurrency())
{
try
{
for (unsigned i = 0; i < thread_count; ++i)
{
threads.push_back(thread_t(&thread_pool::worker_thread, this));
}
}
catch (...)
{
close();
throw;
}
}
/**
* Effects: Destroys the thread pool.
* Synchronization: The completion of all the closures happen before the completion of the thread pool destructor.
*/
~thread_pool()
{
// signal to all the worker threads that there will be no more submissions.
close();
// joins all the threads as the threads were scoped_threads
}
/**
* Effects: close the thread_pool for submissions. The worker threads will work until
*/
void close()
{
work_queue.close();
}
/**
* Returns: whether the pool is closed for submissions.
*/
bool is_closed()
{
return work_queue.closed();
}
/**
* Effects: The specified function will be scheduled for execution at some point in the future.
* If invoking closure throws an exception the thread pool will call std::terminate, as is the case with threads.
* Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
* Throws: sync_queue_is_closed if the thread pool is closed.
*
*/
template <typename Closure>
void submit(Closure const& closure)
{
work w ((closure));
work_queue.push(boost::move(w));
//work_queue.push(work(closure));
}
template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w =boost::move(closure);
work_queue.push(boost::move(w));
//work_queue.push(work(boost::move(closure)));
}
/**
* This must be called from an scheduled task.
* Effects: reschedule functions until pred()
*/
template <typename Pred>
void reschedule_until(Pred const& pred)
{
do {
schedule_one_or_yield();
} while (! pred());
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -15,7 +15,7 @@
#include <boost/assert.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/detail/interlocked.hpp>
//#include <boost/detail/winapi/synchronization.hpp>
//#include <boost/detail/win/synchronization.hpp>
#include <algorithm>
#ifndef BOOST_THREAD_WIN32_HAS_GET_TICK_COUNT_64

View File

@@ -27,6 +27,15 @@
#include <unistd.h>
#endif
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <string>
#include <set>
#include <vector>
#include "./timeconv.inl"
namespace boost
@@ -217,7 +226,7 @@ namespace boost
thread_data_base* make_external_thread_data()
{
thread_data_base* const me(new externally_launched_thread());
thread_data_base* const me(detail::heap_new<externally_launched_thread>());
me->self.reset(me);
set_current_thread_data(me);
return me;
@@ -543,6 +552,56 @@ namespace boost
#endif
}
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
{
#ifdef __linux__
try {
using namespace std;
ifstream proc_cpuinfo ("/proc/cpuinfo");
unsigned current_processor = 0;
const string physical_id("physical id"), core_id("core id");
typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
std::set<core_entry> cores;
core_entry current_core_entry;
for (string line; getline(proc_cpuinfo, line); ) {
vector<string> key_val(2);
boost::split(key_val, line, boost::is_any_of(":"));
string key = key_val[0];
string value = key_val[1];
boost::trim(key);
boost::trim(value);
if (key == physical_id) {
current_core_entry.first = boost::lexical_cast<unsigned>(value);
continue;
}
if (key == core_id) {
current_core_entry.second = boost::lexical_cast<unsigned>(value);
cores.insert(current_core_entry);
continue;
}
}
return cores.size();
} catch(...) {
return 0;
}
#elif defined(__APPLE__)
int count;
size_t size=sizeof(count);
return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
#else
return hardware_concurrency();
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
void thread::interrupt()
{
@@ -670,7 +729,7 @@ namespace boost
{
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);
heap_new<thread_exit_callback_node>(func,current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}

328
src/shared_mutex.cpp Normal file
View File

@@ -0,0 +1,328 @@
// Copyright Howard Hinnant 2007-2010.
// Copyright Vicente J. Botet Escriba 2012.
// 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/v2/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
namespace boost
{
namespace thread_v2
{
// shared_mutex
shared_mutex::shared_mutex()
: state_(0)
{
}
shared_mutex::~shared_mutex()
{
boost::lock_guard<mutex_t> _(mut_);
}
// Exclusive ownership
void
shared_mutex::lock()
{
boost::unique_lock<mutex_t> lk(mut_);
while (state_ & write_entered_)
gate1_.wait(lk);
state_ |= write_entered_;
while (state_ & n_readers_)
gate2_.wait(lk);
}
bool
shared_mutex::try_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
if (state_ == 0)
{
state_ = write_entered_;
return true;
}
return false;
}
void
shared_mutex::unlock()
{
boost::lock_guard<mutex_t> _(mut_);
state_ = 0;
gate1_.notify_all();
}
// Shared ownership
void
shared_mutex::lock_shared()
{
boost::unique_lock<mutex_t> lk(mut_);
while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
gate1_.wait(lk);
count_t num_readers = (state_ & n_readers_) + 1;
state_ &= ~n_readers_;
state_ |= num_readers;
}
bool
shared_mutex::try_lock_shared()
{
boost::unique_lock<mutex_t> lk(mut_);
count_t num_readers = state_ & n_readers_;
if (!(state_ & write_entered_) && num_readers != n_readers_)
{
++num_readers;
state_ &= ~n_readers_;
state_ |= num_readers;
return true;
}
return false;
}
void
shared_mutex::unlock_shared()
{
boost::lock_guard<mutex_t> _(mut_);
count_t num_readers = (state_ & n_readers_) - 1;
state_ &= ~n_readers_;
state_ |= num_readers;
if (state_ & write_entered_)
{
if (num_readers == 0)
gate2_.notify_one();
}
else
{
if (num_readers == n_readers_ - 1)
gate1_.notify_one();
}
}
// upgrade_mutex
upgrade_mutex::upgrade_mutex()
: gate1_(),
gate2_(),
state_(0)
{
}
upgrade_mutex::~upgrade_mutex()
{
boost::lock_guard<mutex_t> _(mut_);
}
// Exclusive ownership
void
upgrade_mutex::lock()
{
boost::unique_lock<mutex_t> lk(mut_);
while (state_ & (write_entered_ | upgradable_entered_))
gate1_.wait(lk);
state_ |= write_entered_;
while (state_ & n_readers_)
gate2_.wait(lk);
}
bool
upgrade_mutex::try_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
if (state_ == 0)
{
state_ = write_entered_;
return true;
}
return false;
}
void
upgrade_mutex::unlock()
{
boost::lock_guard<mutex_t> _(mut_);
state_ = 0;
gate1_.notify_all();
}
// Shared ownership
void
upgrade_mutex::lock_shared()
{
boost::unique_lock<mutex_t> lk(mut_);
while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
gate1_.wait(lk);
count_t num_readers = (state_ & n_readers_) + 1;
state_ &= ~n_readers_;
state_ |= num_readers;
}
bool
upgrade_mutex::try_lock_shared()
{
boost::unique_lock<mutex_t> lk(mut_);
count_t num_readers = state_ & n_readers_;
if (!(state_ & write_entered_) && num_readers != n_readers_)
{
++num_readers;
state_ &= ~n_readers_;
state_ |= num_readers;
return true;
}
return false;
}
void
upgrade_mutex::unlock_shared()
{
boost::lock_guard<mutex_t> _(mut_);
count_t num_readers = (state_ & n_readers_) - 1;
state_ &= ~n_readers_;
state_ |= num_readers;
if (state_ & write_entered_)
{
if (num_readers == 0)
gate2_.notify_one();
}
else
{
if (num_readers == n_readers_ - 1)
gate1_.notify_one();
}
}
// Upgrade ownership
void
upgrade_mutex::lock_upgrade()
{
boost::unique_lock<mutex_t> lk(mut_);
while ((state_ & (write_entered_ | upgradable_entered_)) ||
(state_ & n_readers_) == n_readers_)
gate1_.wait(lk);
count_t num_readers = (state_ & n_readers_) + 1;
state_ &= ~n_readers_;
state_ |= upgradable_entered_ | num_readers;
}
bool
upgrade_mutex::try_lock_upgrade()
{
boost::unique_lock<mutex_t> lk(mut_);
count_t num_readers = state_ & n_readers_;
if (!(state_ & (write_entered_ | upgradable_entered_))
&& num_readers != n_readers_)
{
++num_readers;
state_ &= ~n_readers_;
state_ |= upgradable_entered_ | num_readers;
return true;
}
return false;
}
void
upgrade_mutex::unlock_upgrade()
{
{
boost::lock_guard<mutex_t> _(mut_);
count_t num_readers = (state_ & n_readers_) - 1;
state_ &= ~(upgradable_entered_ | n_readers_);
state_ |= num_readers;
}
gate1_.notify_all();
}
// Shared <-> Exclusive
bool
upgrade_mutex::try_unlock_shared_and_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
if (state_ == 1)
{
state_ = write_entered_;
return true;
}
return false;
}
void
upgrade_mutex::unlock_and_lock_shared()
{
{
boost::lock_guard<mutex_t> _(mut_);
state_ = 1;
}
gate1_.notify_all();
}
// Shared <-> Upgrade
bool
upgrade_mutex::try_unlock_shared_and_lock_upgrade()
{
boost::unique_lock<mutex_t> lk(mut_);
if (!(state_ & (write_entered_ | upgradable_entered_)))
{
state_ |= upgradable_entered_;
return true;
}
return false;
}
void
upgrade_mutex::unlock_upgrade_and_lock_shared()
{
{
boost::lock_guard<mutex_t> _(mut_);
state_ &= ~upgradable_entered_;
}
gate1_.notify_all();
}
// Upgrade <-> Exclusive
void
upgrade_mutex::unlock_upgrade_and_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
count_t num_readers = (state_ & n_readers_) - 1;
state_ &= ~(upgradable_entered_ | n_readers_);
state_ |= write_entered_ | num_readers;
while (state_ & n_readers_)
gate2_.wait(lk);
}
bool
upgrade_mutex::try_unlock_upgrade_and_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
if (state_ == (upgradable_entered_ | 1))
{
state_ = write_entered_;
return true;
}
return false;
}
void
upgrade_mutex::unlock_and_lock_upgrade()
{
{
boost::lock_guard<mutex_t> _(mut_);
state_ = upgradable_entered_ | 1;
}
gate1_.notify_all();
}
} // thread_v2
} // boost

View File

@@ -407,6 +407,8 @@ namespace boost
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
}
#endif
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
{
//SYSTEM_INFO info={{0}};
@@ -414,7 +416,28 @@ namespace boost
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
}
#endif
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
{
unsigned cores = 0;
DWORD size = 0;
GetLogicalProcessorInformation(NULL, &size);
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
return 0;
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(size);
if (GetLogicalProcessorInformation(buffer.data(), &size) == FALSE)
return 0;
const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
for (size_t i = 0; i < Elements; ++i) {
if (buffer[i].Relationship == RelationProcessorCore)
++cores;
}
return cores;
}
thread::native_handle_type thread::native_handle()
{

View File

@@ -209,6 +209,7 @@ rule thread-compile ( sources : reqs * : name )
[ thread-test test_thread.cpp ]
[ thread-test test_thread_id.cpp ]
[ thread-test test_hardware_concurrency.cpp ]
[ thread-test test_physical_concurrency.cpp ]
[ thread-test test_thread_move.cpp ]
[ thread-test test_thread_return_local.cpp ]
[ thread-test test_thread_move_return.cpp ]
@@ -716,6 +717,8 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2 ../example/producer_consumer.cpp : ex_producer_consumer ]
[ thread-run2 ../example/not_interleaved.cpp : ex_not_interleaved ]
[ thread-run2 ../example/lambda_future.cpp : ex_lambda_future ]
[ thread-run2 ../example/not_interleaved2.cpp : ex_not_interleaved2 ]
[ thread-run2 ../example/thread_pool.cpp : ex_thread_pool ]
;
@@ -792,8 +795,11 @@ rule thread-compile ( sources : reqs * : name )
#[ thread-run test_8600.cpp ]
#[ thread-run test_8943.cpp ]
#[ thread-run test_8960.cpp ]
[ thread-run test_9079_a.cpp ]
[ thread-run test_9079_b.cpp ]
#[ thread-run test_9079_a.cpp ]
#[ thread-run test_9079_b.cpp ]
#[ thread-run clang_main.cpp ]
;

View File

@@ -15,6 +15,26 @@
#include <boost/detail/lightweight_test.hpp>
class non_copyable
{
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
int val;
public:
non_copyable() {}
non_copyable(int v) : val(v){}
non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {}
non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; }
bool operator==(non_copyable const& x) const {return val==x.val;}
template <typename OSTREAM>
friend OSTREAM& operator <<(OSTREAM& os, non_copyable const&x )
{
os << x.val;
return os;
}
};
int main()
{
@@ -55,6 +75,16 @@ int main()
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue push rvalue succeeds
boost::sync_bounded_queue<non_copyable> q(2);
non_copyable nc(1);
q.push(boost::move(nc));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue push rvalue succeeds
boost::sync_bounded_queue<int> q(2);
@@ -84,6 +114,16 @@ int main()
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue try_push rvalue succeeds
boost::sync_bounded_queue<non_copyable> q(2);
non_copyable nc(1);
BOOST_TEST(q.try_push(boost::move(nc)));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue try_push value succeeds
boost::sync_bounded_queue<int> q(2);
@@ -103,6 +143,16 @@ int main()
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue try_push rvalue succeeds
boost::sync_bounded_queue<non_copyable> q(2);
non_copyable nc(1);
BOOST_TEST(q.try_push(boost::no_block, boost::move(nc)));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue pull succeed
boost::sync_bounded_queue<int> q(2);
@@ -115,6 +165,19 @@ int main()
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue pull succeed
boost::sync_bounded_queue<non_copyable> q(2);
non_copyable nc(1);
q.push(boost::move(nc));
non_copyable nc2(2);
q.pull(nc2);
BOOST_TEST_EQ(nc, nc2);
BOOST_TEST(q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue pull succeed
boost::sync_bounded_queue<int> q(2);

View File

@@ -15,6 +15,26 @@
#include <boost/detail/lightweight_test.hpp>
class non_copyable
{
BOOST_THREAD_MOVABLE_ONLY(non_copyable)
int val;
public:
non_copyable(int v) : val(v){}
non_copyable(BOOST_RV_REF(non_copyable) x): val(x.val) {}
non_copyable& operator=(BOOST_RV_REF(non_copyable) x) { val=x.val; return *this; }
bool operator==(non_copyable const& x) const {return val==x.val;}
template <typename OSTREAM>
friend OSTREAM& operator <<(OSTREAM& os, non_copyable const&x )
{
os << x.val;
return os;
}
};
int main()
{
@@ -46,7 +66,7 @@ int main()
BOOST_TEST(! q.closed());
}
{
// empty queue push rvalue succeeds
// empty queue push rvalue/copyable succeeds
boost::sync_queue<int> q;
q.push(1);
BOOST_TEST(! q.empty());
@@ -54,6 +74,38 @@ int main()
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue push lvalue/copyable succeeds
boost::sync_queue<int> q;
int i;
q.push(i);
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
#if 0
{
// empty queue push rvalue/non_copyable succeeds
boost::sync_queue<non_copyable> q;
q.push(non_copyable(1));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
#endif
{
// empty queue push rvalue/non_copyable succeeds
boost::sync_queue<non_copyable> q;
non_copyable nc(1);
q.push(boost::move(nc));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue push rvalue succeeds
boost::sync_queue<int> q;
@@ -65,7 +117,7 @@ int main()
BOOST_TEST(! q.closed());
}
{
// empty queue push value succeeds
// empty queue push lvalue succeeds
boost::sync_queue<int> q;
int i;
q.push(i);
@@ -75,7 +127,7 @@ int main()
BOOST_TEST(! q.closed());
}
{
// empty queue try_push rvalue succeeds
// empty queue try_push rvalue/copyable succeeds
boost::sync_queue<int> q;
BOOST_TEST(q.try_push(1));
BOOST_TEST(! q.empty());
@@ -84,7 +136,38 @@ int main()
BOOST_TEST(! q.closed());
}
{
// empty queue try_push value succeeds
// empty queue try_push rvalue/copyable succeeds
boost::sync_queue<int> q;
BOOST_TEST(q.try_push(1));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
#if 0
{
// empty queue try_push rvalue/non-copyable succeeds
boost::sync_queue<non_copyable> q;
BOOST_TEST(q.try_push(non_copyable()));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
#endif
{
// empty queue try_push rvalue/non-copyable succeeds
boost::sync_queue<non_copyable> q;
non_copyable nc(1);
BOOST_TEST(q.try_push(boost::move(nc)));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// empty queue try_push lvalue succeeds
boost::sync_queue<int> q;
int i;
BOOST_TEST(q.try_push(i));
@@ -102,6 +185,27 @@ int main()
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
#if 0
{
// empty queue try_push rvalue/non-copyable succeeds
boost::sync_queue<non_copyable> q;
BOOST_TEST(q.try_push(boost::no_block, non_copyable(1)));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
#endif
{
// empty queue try_push rvalue/non-copyable succeeds
boost::sync_queue<non_copyable> q;
non_copyable nc(1);
BOOST_TEST(q.try_push(boost::no_block, boost::move(nc)));
BOOST_TEST(! q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 1u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue pull succeed
boost::sync_queue<int> q;
@@ -114,6 +218,19 @@ int main()
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue pull succeed
boost::sync_queue<non_copyable> q;
non_copyable nc1(1);
q.push(boost::move(nc1));
non_copyable nc2(2);
q.pull(nc2);
BOOST_TEST_EQ(nc1, nc2);
BOOST_TEST(q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue pull succeed
boost::sync_queue<int> q;
@@ -125,6 +242,18 @@ int main()
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue pull succeed
boost::sync_queue<non_copyable> q;
non_copyable nc1(1);
q.push(boost::move(nc1));
non_copyable nc = q.pull();
BOOST_TEST_EQ(nc, nc1);
BOOST_TEST(q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue try_pull succeed
boost::sync_queue<int> q;
@@ -137,6 +266,19 @@ int main()
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue try_pull succeed
boost::sync_queue<non_copyable> q;
non_copyable nc1(1);
q.push(boost::move(nc1));
non_copyable nc(2);
BOOST_TEST(q.try_pull(nc));
BOOST_TEST_EQ(nc, nc1);
BOOST_TEST(q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue try_pull succeed
boost::sync_queue<int> q;
@@ -149,6 +291,19 @@ int main()
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue try_pull succeed
boost::sync_queue<non_copyable> q;
non_copyable nc1(1);
q.push(boost::move(nc1));
non_copyable nc(2);
BOOST_TEST(q.try_pull(boost::no_block, nc));
BOOST_TEST_EQ(nc, nc1);
BOOST_TEST(q.empty());
BOOST_TEST(! q.full());
BOOST_TEST_EQ(q.size(), 0u);
BOOST_TEST(! q.closed());
}
{
// 1-element queue try_pull succeed
boost::sync_queue<int> q;

18
test/test_8586.cpp Normal file
View File

@@ -0,0 +1,18 @@
// Copyright (C) 2013 Vicente Botet
//
// 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 <iostream>
void hello_world()
{
std::cout << "Hello from thread!" << std::endl;
}
int main()
{
boost::thread my_thread(&hello_world);
my_thread.join();
}

140
test/test_8600.cpp Normal file
View File

@@ -0,0 +1,140 @@
// Copyright (C) 2013 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <vector>
#include <utility>
#include <type_traits>
#if 1
struct B {
int v;
B(int i) : v(i) {}
};
struct D: B {
D(int i) : B(i) {}
};
void fb(B const&) {}
void fd(D const&) {}
BOOST_STATIC_ASSERT(sizeof(B)==sizeof(D));
template <class T, class Allocator=std::allocator<T> >
class new_vector;
template <class T, class Allocator>
class new_vector : public std::vector<T,Allocator>
{
typedef std::vector<T,Allocator> base_type;
public:
new_vector() : base_type() {}
new_vector(unsigned s) : base_type(s) {}
};
template <class Allocator >
class new_vector<bool, Allocator>
{
//std::vector<char,typename Allocator::template rebind<char>::other > v;
int i;
public:
};
template <class T, class A>
typename std::enable_if<!std::is_same<T, bool>::value,
new_vector<T,A>&
>::type
new_vector_cast(std::vector<T,A> & v) {
return reinterpret_cast<new_vector<T,A>&>(v);
}
BOOST_STATIC_ASSERT(sizeof(std::vector<int>)==sizeof(new_vector<int>));
BOOST_STATIC_ASSERT(sizeof(std::vector<bool>)!=sizeof(new_vector<bool>));
void fb(std::vector<int> const&) {}
void fd(new_vector<int> const&) {}
int main() {
{
std::vector<int> b(1);
b[0] = 1;
new_vector<int> d = new_vector_cast(b);
BOOST_ASSERT(b[0] == d[0]);
}
{
//std::vector<bool> b;
//new_vector<bool> d = new_vector_cast(b); // compile fail
}
{
std::vector<int> b(1);
b[0] = 1;
fd(new_vector_cast(b));
}
{
new_vector<int> d(1);
d[0] = 1;
std::vector<int> b = d;
BOOST_ASSERT(b[0] == d[0]);
}
{
//new_vector<bool> d;
//std::vector<bool> b = d; // compile fail
}
{
new_vector<int> d(1);
d[0] = 1;
fd(d);
}
return 0;
}
#else
int main() {
{
B b(1);
D d = reinterpret_cast<D&>(b);
BOOST_ASSERT(b.v == d.v);
}
{
B b(1);
fd(reinterpret_cast<D&>(b));
}
{
D d(2);
B b = d;
BOOST_ASSERT(b.v == d.v);
}
{
D d(2);
fd(d);
}
return 0;
}
#define BOOST_THREAD_VERSION 4
#include <iostream>
#include <boost/thread.hpp>
int calculate_the_answer_to_life_the_universe_and_everything()
{
return 42;
}
int main()
{
boost::packaged_task<int()> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost::shared_future<int> fi1 = boost::shared_future<int>(pt.get_future());
boost::shared_future<int> fi2 = fi1;
boost::thread task(boost::move(pt)); // launch task on a thread
boost::wait_for_any(fi1, fi2);
std::cout << "Wait for any returned\n";
return (0);
}
#endif

47
test/test_8943.cpp Normal file
View File

@@ -0,0 +1,47 @@
// Copyright (C) 2013 Vicente Botet
//
// 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/detail/lightweight_test.hpp>
#if defined(WIN32)
#include <tchar.h>
#endif
#include <cstdlib>
#include <iostream>
#include <boost/thread/once.hpp>
namespace {
class foo
{
public:
void operator()() const
{
std::cout << "foo" << std::endl;
}
}; // class foo
}
#if defined(WIN32)
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
#else
int main(int /*argc*/, char* /*argv*/[])
#endif
{
try
{
boost::once_flag once_flag = BOOST_ONCE_INIT;
boost::call_once(once_flag, foo());
return EXIT_SUCCESS;
}
catch (...)
{
std::cerr << "Unknown exception" << std::endl;
BOOST_TEST(false);
}
return boost::report_errors();
}

53
test/test_8960.cpp Normal file
View File

@@ -0,0 +1,53 @@
// Copyright (C) 2013 Vicente Botet
//
// 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 <iostream>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/chrono.hpp>
//#include <boost/bind.hpp>
#include <boost/detail/lightweight_test.hpp>
void do_thread()
{
try
{
boost::condition_variable c1;
boost::mutex m1;
boost::unique_lock<boost::mutex> l1(m1);
c1.wait_for(l1, boost::chrono::seconds(1));
}
catch (std::runtime_error& ex)
{
std::cout << "EXCEPTION ! " << ex.what() << std::endl;
BOOST_TEST(false);
}
catch (...)
{
std::cout << "EXCEPTION ! " << std::endl;
BOOST_TEST(false);
}
}
int main()
{
boost::thread th1(&do_thread);
th1.join();
//std::string s1;
//std::cin >> s1;
return boost::report_errors();
}

View File

@@ -0,0 +1,24 @@
// Copyright (C) 2007 Anthony Williams
// Copyright (C) 2013 Tim Blechmann
//
// 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_only.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
void test_physical_concurrency_is_non_zero()
{
BOOST_CHECK(boost::thread::physical_concurrency()!=0);
}
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: physical concurrency test suite");
test->add(BOOST_TEST_CASE(test_physical_concurrency_is_non_zero));
return test;
}