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()18inline 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()49int 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