21
21
namespace azure { namespace storage { namespace core {
22
22
23
23
timer_handler::timer_handler (const pplx::cancellation_token& token) :
24
- m_cancellation_token (token), m_is_canceled_by_timeout(false )
24
+ m_cancellation_token (token), m_is_canceled_by_timeout(false ), m_timer_started( false )
25
25
{
26
- m_worker_cancellation_token_source = std::make_shared<pplx::cancellation_token_source>();
27
26
if (m_cancellation_token != pplx::cancellation_token::none ())
28
27
{
29
28
m_cancellation_token_registration = m_cancellation_token.register_callback ([this ]()
30
29
{
31
- this -> m_worker_cancellation_token_source -> cancel ();
32
- this -> stop_timer ();
30
+ m_worker_cancellation_token_source. cancel ();
31
+ stop_timer ();
33
32
});
34
33
}
35
34
}
@@ -41,67 +40,66 @@ namespace azure { namespace storage { namespace core {
41
40
m_cancellation_token.deregister_callback (m_cancellation_token_registration);
42
41
}
43
42
44
- #ifdef _WIN32
45
43
stop_timer ();
46
- #else // LINUX
47
- try
48
- {
49
- stop_timer ();
50
- }
51
- catch (boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> > &e)
52
- {
53
- }
54
- #endif
55
-
56
44
}
57
45
58
46
void timer_handler::start_timer (const std::chrono::milliseconds& time)
59
47
{
60
- m_mutex = std::make_shared<std::mutex>();
61
- auto this_pointer = std::dynamic_pointer_cast<timer_handler>(shared_from_this ());
62
- m_timeout_task = timeout_after (time).then ([this_pointer]()
48
+ std::lock_guard<std::mutex> guard (m_mutex);
49
+ if (m_timer_started.load (std::memory_order_acquire))
50
+ {
51
+ return ;
52
+ }
53
+ m_timer_started.store (true , std::memory_order_release);
54
+ std::weak_ptr<timer_handler> weak_this_pointer = shared_from_this ();
55
+ m_timeout_task = timeout_after (time).then ([weak_this_pointer]()
63
56
{
64
- this_pointer->m_is_canceled_by_timeout = true ;
65
- this_pointer->m_worker_cancellation_token_source ->cancel ();
57
+ auto this_pointer = weak_this_pointer.lock ();
58
+ if (this_pointer)
59
+ {
60
+ this_pointer->m_is_canceled_by_timeout .store (true , std::memory_order_release);
61
+ this_pointer->m_worker_cancellation_token_source .cancel ();
62
+ }
66
63
});
67
64
}
68
65
69
66
void timer_handler::stop_timer ()
70
67
{
71
- if (m_timer != nullptr )
68
+ std::lock_guard<std::mutex> guard (m_mutex);
69
+ if (m_timer_started.load (std::memory_order_acquire) && m_timer)
72
70
{
73
- std::lock_guard<std::mutex> guard (*m_mutex);
74
- if (m_timer != nullptr )
75
- {
76
71
#ifndef _WIN32
77
- m_timer->cancel ();
72
+ m_timer->cancel ();
78
73
#else
79
- m_timer->stop ();
74
+ m_timer->stop ();
80
75
#endif
81
- if (!m_tce._IsTriggered ())
82
- {
83
- // if task_completion_event is not yet triggered, it means timeout has not been triggered.
84
- m_tce._Cancel ();
85
- }
86
- m_timer.reset ();
76
+ if (!m_tce._IsTriggered ())
77
+ {
78
+ // If task_completion_event is not yet triggered, it means timeout has not been triggered.
79
+ m_tce._Cancel ();
87
80
}
81
+ m_timer.reset ();
88
82
}
89
83
}
90
84
91
85
#ifndef _WIN32
92
86
pplx::task<void > timer_handler::timeout_after (const std::chrono::milliseconds& time)
93
87
{
94
- m_timer = std::make_shared<boost::asio::basic_waitable_timer<std_clock >>(crossplat::threadpool::shared_instance ().service ());
95
- m_timer->expires_from_now (std::chrono::duration_cast<std_clock ::duration>(time));
96
- auto this_pointer = std::dynamic_pointer_cast <timer_handler>( shared_from_this () );
97
- auto callback = [this_pointer ](const boost::system::error_code& ec)
88
+ m_timer = std::make_shared<boost::asio::basic_waitable_timer<std::chrono::steady_clock >>(crossplat::threadpool::shared_instance ().service ());
89
+ m_timer->expires_from_now (std::chrono::duration_cast<std::chrono::steady_clock ::duration>(time));
90
+ std::weak_ptr <timer_handler> weak_this_pointer = shared_from_this ();
91
+ auto callback = [weak_this_pointer ](const boost::system::error_code& ec)
98
92
{
99
93
if (ec != boost::asio::error::operation_aborted)
100
94
{
101
- std::lock_guard<std::mutex> guard (*( this_pointer-> m_mutex ) );
102
- if (! this_pointer-> m_tce . _IsTriggered () )
95
+ auto this_pointer = weak_this_pointer. lock ( );
96
+ if (this_pointer)
103
97
{
104
- this_pointer->m_tce .set ();
98
+ std::lock_guard<std::mutex> guard (this_pointer->m_mutex );
99
+ if (!this_pointer->m_tce ._IsTriggered ())
100
+ {
101
+ this_pointer->m_tce .set ();
102
+ }
105
103
}
106
104
}
107
105
};
@@ -114,23 +112,27 @@ namespace azure { namespace storage { namespace core {
114
112
#else
115
113
pplx::task<void > timer_handler::timeout_after (const std::chrono::milliseconds& time)
116
114
{
117
- // initialize the timer and connect the callback with completion event.
115
+ // Initialize the timer and connect the callback with completion event.
118
116
m_timer = std::make_shared<concurrency::timer<int >>(static_cast <unsigned int >(time.count ()), 0 );
119
- auto this_pointer = std::dynamic_pointer_cast <timer_handler>( shared_from_this () );
120
- auto callback = std::make_shared<concurrency::call<int >>([this_pointer ](int )
117
+ std::weak_ptr <timer_handler> weak_this_pointer = shared_from_this ();
118
+ auto callback = std::make_shared<concurrency::call<int >>([weak_this_pointer ](int )
121
119
{
122
- std::lock_guard<std::mutex> guard (*( this_pointer-> m_mutex ) );
123
- if (! this_pointer-> m_tce . _IsTriggered () )
120
+ auto this_pointer = weak_this_pointer. lock ( );
121
+ if (this_pointer)
124
122
{
125
- this_pointer->m_tce .set ();
123
+ std::lock_guard<std::mutex> guard (this_pointer->m_mutex );
124
+ if (!this_pointer->m_tce ._IsTriggered ())
125
+ {
126
+ this_pointer->m_tce .set ();
127
+ }
126
128
}
127
129
});
128
- m_timer->link_target (callback.get ());// When timer stops, tce will trigger cancellation.
130
+ m_timer->link_target (callback.get ()); // When timer stops, tce will trigger cancellation.
129
131
m_timer->start ();
130
132
131
133
auto event_set = pplx::create_task (m_tce);
132
134
133
- // timer and callback should be preserved before event set has been triggered.
135
+ // Timer and callback should be preserved before event set has been triggered.
134
136
return event_set.then ([callback]() {});
135
137
}
136
138
#endif
0 commit comments