c++11实现异步定时器
c++11实现异步定时器
c++11提供了丰富的时间和线程操作函数,比如 std::this_thread::sleep, std::chrono::seconds等。可以利用这些来很方便的实现一个定时器。
定时器要求在固定的时间异步执行一个操作,比如boost库中的boost::asio::deadline_timer,以及MFC中的定时器。这里,利用c++11的thread, mutex, condition_variable 来实现一个定时器:
定时器要求异步执行任务 —-> 开辟独立的线程
定时器要求能够启动和取消 —-> 提供安全的取消操作,使用互斥量和信号量
定时器要求每个定时时刻到达的时候执行的任务要尽可能节省时间
实现
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#ifndef TIMER_H_#define TIMER_H_#include<functional>#include<chrono>#include<thread>#include<atomic>#include<memory>#include<mutex>#include<condition_variable>class Timer{public: Timer() :expired_(true), try_to_expire_(false){ } Timer(const Timer& t){ expired_ = t.expired_.load(); try_to_expire_ = t.try_to_expire_.load(); } ~Timer(){ Expire(); // std::cout << "timer destructed!" << std::endl; } void StartTimer(int interval, std::function<void()> task){ if (expired_ == false){ // std::cout << "timer is currently running, please expire it first..." << std::endl; return; } expired_ = false; std::thread([this, interval, task](){ while (!try_to_expire_){ std::this_thread::sleep_for(std::chrono::milliseconds(interval)); task(); } // std::cout << "stop task..." << std::endl; { std::lock_guard<std::mutex> locker(mutex_); expired_ = true; expired_cond_.notify_one(); } }).detach(); } void Expire(){ if (expired_){ return; } if (try_to_expire_){ // std::cout << "timer is trying to expire, please wait..." << std::endl; return; } try_to_expire_ = true; { std::unique_lock<std::mutex> locker(mutex_); expired_cond_.wait(locker, [this]{return expired_ == true; }); if (expired_ == true){ // std::cout << "timer expired!" << std::endl; try_to_expire_ = false; } } } template<typename callable, class... arguments> void SyncWait(int after, callable&& f, arguments&&... args){ std::function<typename std::result_of<callable(arguments...)>::type()> task (std::bind(std::forward<callable>(f), std::forward<arguments>(args)...)); std::this_thread::sleep_for(std::chrono::milliseconds(after)); task(); } template<typename callable, class... arguments> void AsyncWait(int after, callable&& f, arguments&&... args){ std::function<typename std::result_of<callable(arguments...)>::type()> task (std::bind(std::forward<callable>(f), std::forward<arguments>(args)...)); std::thread([after, task](){ std::this_thread::sleep_for(std::chrono::milliseconds(after)); task(); }).detach(); } private: std::atomic<bool> expired_; std::atomic<bool> try_to_expire_; std::mutex mutex_; std::condition_variable expired_cond_;};#endif////////////////////test.cpp#include<iostream>#include<string>#include<memory>#include"Timer.hpp"using namespace std;void EchoFunc(std::string&& s){ std::cout << "test : " << s << endl;}int main(){ Timer t; //周期性执行定时任务 t.StartTimer(1000, std::bind(EchoFunc,"hello world!")); std::this_thread::sleep_for(std::chrono::seconds(4)); std::cout << "try to expire timer!" << std::endl; t.Expire(); //周期性执行定时任务 t.StartTimer(1000, std::bind(EchoFunc, "hello c++11!")); std::this_thread::sleep_for(std::chrono::seconds(4)); std::cout << "try to expire timer!" << std::endl; t.Expire(); std::this_thread::sleep_for(std::chrono::seconds(2)); //只执行一次定时任务 //同步 t.SyncWait(1000, EchoFunc, "hello world!"); //异步 t.AsyncWait(1000, EchoFunc, "hello c++11!"); std::this_thread::sleep_for(std::chrono::seconds(2)); return 0;} |

/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_FRAMEWORK_CANCELLATION_H_
#define TENSORFLOW_FRAMEWORK_CANCELLATION_H_
#include
#include
#include “tensorflow/core/lib/core/notification.h”
#include “tensorflow/core/lib/core/status.h”
#include “tensorflow/core/lib/gtl/flatmap.h”
#include “tensorflow/core/lib/hash/hash.h”
#include “tensorflow/core/platform/mutex.h”
#include “tensorflow/core/platform/thread_annotations.h”
#include “tensorflow/core/platform/types.h”
namespace tensorflow {
// A token that can be used to register and deregister a
// CancelCallback with a CancellationManager.
//
// CancellationToken values must be created by a call to
// CancellationManager::get_cancellation_token.
typedef int64 CancellationToken;
// A callback that is invoked when a step is canceled. CancelCallback;
//
// NOTE(mrry): See caveats about CancelCallback implementations in the
// comment for CancellationManager::RegisterCallback.
typedef std::function
class CancellationManager {
public:
// A value that won’t be returned by get_cancellation_token().
static const CancellationToken kInvalidToken;
CancellationManager();
~CancellationManager();
// Run all callbacks associated with this manager.
void StartCancel();
// Returns true iff StartCancel() has been called.
bool IsCancelled() { return is_cancelled_.load(std::memory_order_acquire); }
// Returns a token that must be used in calls to RegisterCallback
// and DeregisterCallback.
CancellationToken get_cancellation_token();
// Attempts to register the given callback to be invoked when this callback) {
// manager is cancelled. Returns true if the callback was
// registered; returns false if this manager was already cancelled,
// and the callback was not registered.
//
// If this method returns false, it is the caller’s responsibility
// to perform any cancellation cleanup.
//
// This method is tricky to use correctly. The following usage pattern
// is recommended:
//
// class ObjectWithCancellableOperation {
// mutex mu_;
// void CancellableOperation(CancellationManager* cm,
// std::function
// bool already_cancelled;
// CancellationToken token = cm->get_cancellation_token();
// {
// mutex_lock(mu_);
// already_cancelled = !cm->RegisterCallback(
// [this, token]() { Cancel(token); });
// if (!already_cancelled) {
// // Issue asynchronous operation. Associate the pending operation
// // with `token` in some object state, or provide another way for
// // the Cancel method to look up the operation for cancellation.
// // Ensure that `cm->DeregisterCallback(token)` is called without
// // holding `mu_`, before `callback` is invoked.
// // …
// }
// }
// if (already_cancelled) {
// callback(errors::Cancelled(“Operation was cancelled”));
// }
// }
//
// void Cancel(CancellationToken token) {
// mutex_lock(mu_);
// // Take action to cancel the operation with the given cancellation
// // token.
// }
//
// NOTE(mrry): The caller should take care that (i) the calling code
// is robust to `callback` being invoked asynchronously (e.g. from
// another thread), (ii) `callback` is deregistered by a call to
// this->DeregisterCallback(token) when the operation completes
// successfully, and (iii) `callback` does not invoke any method
// on this cancellation manager. Furthermore, it is important that
// the eventual caller of the complementary DeregisterCallback does not
// hold any mutexes that are required by `callback`.
bool RegisterCallback(CancellationToken token, CancelCallback callback);
// Deregister the callback that, when registered, was associated
// with the given cancellation token. Returns true iff the callback
// was deregistered and will not be invoked; otherwise returns false
// after the callback has been invoked, blocking if necessary.
//
// NOTE(mrry): This method may block if cancellation is in progress.
// The caller of this method must not hold any mutexes that are required
// to invoke any cancellation callback that has been registered with this
// cancellation manager.
bool DeregisterCallback(CancellationToken token);
private:
bool is_cancelling_;
std::atomic_bool is_cancelled_;
mutex mu_; callbacks_ GUARDED_BY(mu_);
Notification cancelled_notification_;
CancellationToken next_cancellation_token_ GUARDED_BY(mu_);
gtl::FlatMap
};
} // namespace tensorflow
#endif // TENSORFLOW_FRAMEWORK_CANCELLATION_H_