mirror of
https://github.com/boostorg/thread.git
synced 2026-02-07 10:52:10 +00:00
Compare commits
38 Commits
boost-1.55
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd51f97e44 | ||
|
|
04e3d918fb | ||
|
|
0073516f0a | ||
|
|
89de3dcf4f | ||
|
|
47f40f991f | ||
|
|
8b351fe473 | ||
|
|
24f1e620e8 | ||
|
|
ed6459ecd2 | ||
|
|
858816b2d2 | ||
|
|
4bc70444a4 | ||
|
|
fcc027369f | ||
|
|
5c78582794 | ||
|
|
7f479a1dec | ||
|
|
4f2a7b2256 | ||
|
|
5c88e6ce61 | ||
|
|
650e374492 | ||
|
|
6319080ef2 | ||
|
|
3ac48bdd65 | ||
|
|
c3c8ada97d | ||
|
|
fd5dd0c2ed | ||
|
|
4a83aa58ed | ||
|
|
7d96aa625c | ||
|
|
d57a4c6565 | ||
|
|
c67e39f126 | ||
|
|
5a3c301582 | ||
|
|
dc5a8a9c4e | ||
|
|
1e49343ff4 | ||
|
|
93d1855e64 | ||
|
|
a39dd7e8b3 | ||
|
|
7e5cb92bab | ||
|
|
62cf0f86f6 | ||
|
|
c12e07754a | ||
|
|
cbc4266774 | ||
|
|
3a038d33e5 | ||
|
|
51ba4be998 | ||
|
|
2d50af8481 | ||
|
|
e438c98070 | ||
|
|
1e2a76de47 |
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
61
example/not_interleaved2.cpp
Normal file
61
example/not_interleaved2.cpp
Normal 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
147
example/thread_pool.cpp
Normal 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;
|
||||
}
|
||||
94
include/boost/thread/detail/function_wrapper.hpp
Normal file
94
include/boost/thread/detail/function_wrapper.hpp
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
35
include/boost/thread/ostream_buffer.hpp
Normal file
35
include/boost/thread/ostream_buffer.hpp
Normal 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
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
192
include/boost/thread/thread_pool.hpp
Normal file
192
include/boost/thread/thread_pool.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
328
src/shared_mutex.cpp
Normal 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
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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 ]
|
||||
|
||||
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
18
test/test_8586.cpp
Normal 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
140
test/test_8600.cpp
Normal 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
47
test/test_8943.cpp
Normal 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
53
test/test_8960.cpp
Normal 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();
|
||||
}
|
||||
24
test/test_physical_concurrency.cpp
Normal file
24
test/test_physical_concurrency.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user