Skip to content

Commit

Permalink
Thread: merge scoped_thread constr + condition_variable timed wait is…
Browse files Browse the repository at this point in the history
…sues on windows + doc typos.

[SVN r85663]
  • Loading branch information
viboes committed Sep 13, 2013
1 parent 5520763 commit 134c323
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 35 deletions.
10 changes: 7 additions & 3 deletions doc/changes.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

[section:changes History]

[/]
[heading Version 4.2.0 - boost 1.55]

[*New Features:]
Expand All @@ -17,15 +16,20 @@
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
* [@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/8515 #8515] Async: Add shared_future::then.
* [@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

[*Fixed Bugs:]

[/]
* [@http://svn.boost.org/trac/boost/ticket/8931 #8931] Typos in external_locking reference
* [@http://svn.boost.org/trac/boost/ticket/9029 #9029] Misprint in documentation
* [@http://svn.boost.org/trac/boost/ticket/9037 #9037] [thread] gcc -Wshadow gives warnings in condition_variable{,_fwd}.hpp
* [@http://svn.boost.org/trac/boost/ticket/9041 #9041] [thread] Boost.Thread DSO's may need to link with Boost.Atomic

[heading Version 4.1.0 - boost 1.54]

Expand Down
8 changes: 4 additions & 4 deletions doc/configuration.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ Define `BOOST_THREAD_DONT_USE_ATOMIC ` if you don't want to use Boost.Atomic or

The following operators are deprecated:

* `boost::thread::oprator==`
* `boost::thread::oprator!=`
* `boost::thread::operator==`
* `boost::thread::operator!=`

When `BOOST_THREAD_PROVIDES_THREAD_EQ` is defined Boost.Thread provides these deprecated feature.

Use instead

* `boost::thread::id::oprator==`
* `boost::thread::id::oprator!=`
* `boost::thread::id::operator==`
* `boost::thread::id::operator!=`

[warning This is a breaking change respect to version 1.x.]

Expand Down
2 changes: 1 addition & 1 deletion doc/external_locking.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ We need a way to transfer the ownership from the `unique_lock` to a `strict_lock

In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable `unlock` or restore the ownership.

This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. Ths is really nice.
This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.

Now we need to state that both classes are `strict_lock`s.

Expand Down
4 changes: 2 additions & 2 deletions doc/scoped_thread.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ This wrapper can be used to join the thread before destroying it seems a natural

explicit scoped_thread(thread&& th) noexcept;
template <typename F&&, typename ...Args>
explicit strict_scoped_thread(F&&, Args&&...);
explicit scoped_thread(F&&, Args&&...);

~scoped_thread();

Expand Down Expand Up @@ -323,7 +323,7 @@ any) to `*this`.
[section:call_constructor Move Constructor from a Callable]

template <typename F&&, typename ...Args>
explicit strict_scoped_thread(F&&, Args&&...);
explicit scoped_thread(F&&, Args&&...);

[variablelist

Expand Down
4 changes: 2 additions & 2 deletions doc/sync_tutorial.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ In addition to the C++11 standard locks, Boost.Thread provides other locks and s
In particular, the library provides some lock factories.

template <class Lockable, class Function>
auto with_lock_guard(Lockable& m, Function f) -> decltype(fn())
auto with_lock_guard(Lockable& m, Function f) -> decltype(f())
{
auto&& _ = boost::make_lock_guard(f);
auto&& _ = boost::make_lock_guard(m);
f();
}

Expand Down
10 changes: 5 additions & 5 deletions doc/thread_ref.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ any) to `*this`.

[variablelist

[[Requires:] [`Callable` must by Copyable and `func()` must be a valid expression.]]
[[Requires:] [`Callable` must be Copyable and `func()` must be a valid expression.]]

[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
Expand All @@ -595,7 +595,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any

[variablelist

[[Preconditions:] [`Callable` must by copyable.]]
[[Preconditions:] [`Callable` must be copyable.]]

[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
Expand Down Expand Up @@ -623,7 +623,7 @@ If the attributes declare the native thread as detached, the boost::thread will

[variablelist

[[Preconditions:] [`Callable` must by Movable.]]
[[Preconditions:] [`Callable` must be Movable.]]

[[Effects:] [`func` is moved into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
Expand All @@ -650,7 +650,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any

[variablelist

[[Preconditions:] [`Callable` must by copyable.]]
[[Preconditions:] [`Callable` must be copyable.]]

[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
Expand Down Expand Up @@ -679,7 +679,7 @@ If the attributes declare the native thread as detached, the boost::thread will

[variablelist

[[Preconditions:] [`F` and each `A`n must by copyable or movable.]]
[[Preconditions:] [`F` and each `A`n must be copyable or movable.]]

[[Effects:] [As if [link
thread.thread_management.thread.callable_constructor
Expand Down
4 changes: 2 additions & 2 deletions example/not_interleaved.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ int main()
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);

scoped_thread<> t1(thread(use_cerr, boost::ref(mcerr)));
scoped_thread<> t2(thread(use_cout, boost::ref(mcout)));
scoped_thread<> t1(boost::thread(use_cerr, boost::ref(mcerr)));
scoped_thread<> t2(boost::thread(use_cout, boost::ref(mcout)));
this_thread::sleep_for(chrono::seconds(2));
std::string nm;
{
Expand Down
6 changes: 3 additions & 3 deletions example/producer_consumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ int main()

{
mcout << "begin of main" << std::endl;
scoped_thread<> t11(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));

this_thread::sleep_for(chrono::seconds(1));

Expand Down
6 changes: 3 additions & 3 deletions example/producer_consumer_bounded.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ int main()

{
mcout << "begin of main" << std::endl;
scoped_thread<> t11(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));

this_thread::sleep_for(chrono::seconds(1));

Expand Down
8 changes: 7 additions & 1 deletion example/scoped_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ void do_something(int& i)
{
++i;
}
void f(int, int)
{
}

struct func
{
Expand Down Expand Up @@ -81,7 +84,10 @@ int main()

do_something_in_current_thread();
}

{
boost::scoped_thread<> g( f, 1, 2 );
do_something_in_current_thread();
}
return 0;
}

10 changes: 4 additions & 6 deletions include/boost/thread/scoped_thread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ namespace boost
*
*/
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class F, class ...Args>
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args,
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type>
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
#else
template <class F>
Expand Down Expand Up @@ -138,9 +137,8 @@ namespace boost
*/

#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class F, class ...Args>
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args,
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type>
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
#else
template <class F>
Expand Down
19 changes: 17 additions & 2 deletions include/boost/thread/win32/condition_variable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,11 @@ namespace boost
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
do_wait(lock, ceil<milliseconds>(t-Clock::now()).count());
chrono::time_point<Clock, Duration> now = Clock::now();
if (t<=now) {
return cv_status::timeout;
}
do_wait(lock, ceil<milliseconds>(t-now).count());
return Clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
}
Expand All @@ -378,6 +382,10 @@ namespace boost
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d<=chrono::duration<Rep, Period>::zero()) {
return cv_status::timeout;
}

steady_clock::time_point c_now = steady_clock::now();
do_wait(lock, ceil<milliseconds>(d).count());
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
Expand Down Expand Up @@ -479,7 +487,11 @@ namespace boost
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
do_wait(lock, ceil<milliseconds>(t-Clock::now()).count());
chrono::time_point<Clock, Duration> now = Clock::now();
if (t<=now) {
return cv_status::timeout;
}
do_wait(lock, ceil<milliseconds>(t-now).count());
return Clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
}
Expand All @@ -491,6 +503,9 @@ namespace boost
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d<=chrono::duration<Rep, Period>::zero()) {
return cv_status::timeout;
}
steady_clock::time_point c_now = steady_clock::now();
do_wait(lock, ceil<milliseconds>(d).count());
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
Expand Down
4 changes: 3 additions & 1 deletion test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,9 @@ 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 ]

;

}
57 changes: 57 additions & 0 deletions test/test_9079_a.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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)

// A

//#include <boost/log/trivial.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/thread/condition_variable.hpp>

//#if !defined(BOOST_NO_CXX11_ALIGNAS)
//#error
//# define BOOST_ALIGNMENT2(x) alignas(x)
//#elif defined(_MSC_VER)
//#error
//# define BOOST_ALIGNMENT2(x) __declspec(align(x))
//#elif defined(__GNUC__)
//#error
//# define BOOST_ALIGNMENT(x) __attribute__ ((__aligned__(x)))
//#else
//#error
//# define BOOST_NO_ALIGNMENT2
//# define BOOST_ALIGNMENT2(x)
//#endif

typedef boost::chrono::high_resolution_clock Clock;
typedef Clock::time_point TimePoint;

inline TimePoint real_time_now()
{
return Clock::now();
}

int main()
{
using namespace boost::chrono;

boost::condition_variable m_task_spawn_condition;

boost::mutex main_thread_mutex;
boost::unique_lock < boost::mutex > main_thread_lock(main_thread_mutex);

//BOOST_LOG_TRIVIAL(info) << "[TaskScheduler::run_and_wait] Scheduling loop - BEGIN";

//while (true)
{
static const milliseconds TIME_BACK = milliseconds(1);
m_task_spawn_condition.wait_until(
main_thread_lock,
real_time_now() - TIME_BACK); // wait forever
m_task_spawn_condition.wait_for( main_thread_lock, - TIME_BACK ); // same problem
//BOOST_LOG_TRIVIAL(trace) << "TICK";
}

}
Loading

0 comments on commit 134c323

Please sign in to comment.