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 | |
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 | |
29 | bool is_exiting() const |
30 | { |
31 | return m_is_exiting; |
32 | } |
33 | |
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 | |
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(d: boost::chrono::seconds(1)); |
78 | std::cout << next_spawn_time << std::endl; |
79 | m_task_spawn_condition.wait_until( |
80 | lock&: main_thread_lock, |
81 | t: next_spawn_time); // DON'T WORK: WILL WAIT IF next_spawn_time is too close! |
82 | } |
83 | |
84 | } |
85 | |
86 | } |
87 |