1 // Copyright (C) 2013 Vicente Botet
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 // B
7 
8 #include <boost/atomic.hpp>
9 //#include <boost/log/trivial.hpp>
10 #include <boost/chrono.hpp>
11 #include <boost/chrono/chrono_io.hpp>
12 #include <boost/thread.hpp>
13 #include <boost/thread/condition_variable.hpp>
14 
15 typedef boost::chrono::high_resolution_clock Clock;
16 typedef Clock::time_point TimePoint;
17 
real_time_now()18 inline TimePoint real_time_now()
19 {
20   return Clock::now();
21 }
22 
23 class Foo {
24   boost::atomic<bool> m_is_exiting;
25   TimePoint m_next_tick_time;
26 
27 public:
28 
is_exiting() const29   bool is_exiting() const
30   {
31     return m_is_exiting;
32   }
33 
spawn_tasks()34   TimePoint spawn_tasks() // note that in my app, this call takes more time than here
35   {
36     using namespace boost::chrono;
37     const TimePoint now = real_time_now();
38 
39     if (m_next_tick_time < now) {
40       m_next_tick_time = now + seconds(1);
41       //BOOST_LOG_TRIVIAL(info) << "TICK!";
42     }
43 
44     return m_next_tick_time;
45   }
46 
47 };
48 
main()49 int main()
50 {
51   using namespace boost::chrono;
52   static const milliseconds MIN_TIME_TASKS_SPAWN_FREQUENCY = milliseconds(1);
53   //microseconds(1); // THE SHORTER THE QUICKER TO REPRODUCE THE BUG
54 
55   boost::condition_variable m_task_spawn_condition;
56   Foo foo;
57 
58   boost::mutex main_thread_mutex;
59   boost::unique_lock < boost::mutex > main_thread_lock(main_thread_mutex);
60 
61   //BOOST_LOG_TRIVIAL(info) << "[TaskScheduler::run_and_wait] Scheduling loop - BEGIN";
62 
63   int i =11;
64   while (i--)
65   {
66     const TimePoint next_task_spawn_time = foo.spawn_tasks();
67 
68     const TimePoint now = real_time_now();
69     const TimePoint next_minimum_spawn_time = now + MIN_TIME_TASKS_SPAWN_FREQUENCY;
70     const TimePoint next_spawn_time = next_task_spawn_time > TimePoint()
71         && next_task_spawn_time < next_minimum_spawn_time
72         ? next_task_spawn_time : next_minimum_spawn_time;
73 
74     const TimePoint::duration wait_time = next_spawn_time - now;
75     if (wait_time > wait_time.zero()) {
76       // BOOST_LOG_TRIVIAL(trace) << "WAIT TIME: " << wait_time; // UNCOMMENT THIS: MAKES IT WORKS. WAT??????
77       boost::this_thread::sleep_for(boost::chrono::seconds(1));
78       std::cout << next_spawn_time << std::endl;
79       m_task_spawn_condition.wait_until(
80           main_thread_lock,
81           next_spawn_time); // DON'T WORK: WILL WAIT IF next_spawn_time is too close!
82     }
83 
84   }
85 
86 }
87