如何使用C ++ 11创build计时器事件?
如何使用C ++ 11创build计时器事件?
我需要的东西是:“从现在起1秒后给我打电话”。
有没有图书馆?
做一个简单的实现我相信是你想达到的。 您可以later
使用以下参数来使用该类:
- int(等待直到运行代码的毫秒数)
- bool(如果为true,则立即返回,并在另一个线程的指定时间后运行代码)
- 可变参数(正是你喂给std :: bind的东西 )
你可以将std::chrono::milliseconds
更改为std::chrono::nanoseconds
或microseconds
以获得更高的精度,并添加第二个int和for循环来指定运行代码的次数。
在这里,你可以享受:
#include <functional> #include <chrono> #include <future> #include <cstdio> class later { public: template <class callable, class... arguments> later(int after, bool async, callable&& f, arguments&&... args) { std::function<typename std::result_of<callable(arguments...)>::type()> task(std::bind(std::forward<callable>(f), std::forward<arguments>(args)...)); if (async) { std::thread([after, task]() { std::this_thread::sleep_for(std::chrono::milliseconds(after)); task(); }).detach(); } else { std::this_thread::sleep_for(std::chrono::milliseconds(after)); task(); } } }; void test1(void) { return; } void test2(int a) { printf("%i\n", a); return; } int main() { later later_test1(1000, false, &test1); later later_test2(1000, false, &test2, 101); return 0; }
两秒后输出:
101
如果您在Windows上,则可以使用concurrency :: timer类来安排callback,而不必担心线程pipe理,也不会阻塞当前线程。
#include <iostream> #include <agents.h> #include <ppltasks.h> template <class T> void call_after(const T& callback, unsigned int timeInMs) { concurrency::task_completion_event<void> tce; auto call = new concurrency::call<int>( [callback, tce](int) { callback(); tce.set(); }); auto timer = new concurrency::timer<int>(timeInMs, 0, call, false); concurrency::task<void> event_set(tce); event_set.then([timer, call]() { delete call; delete timer; }); timer->start(); } int main() { std::function<void()> callback = []{ std::cout << "in callback\n"; }; call_after(callback, 1000); std::cin.get(); }
也看看这篇文章。
如果你是一个纯粹的Windows爱好者或者不喜欢使用ppl,你可以使用CreateWaitableTimer和RegisterWaitForSingleObject函数在默认的windows线程池中调度callback。
#include <Windows.h> #include <string> #include <iostream> #include <functional> #include <memory> template <class T> class Timer { public: Timer(const T& callback, long long timeInHundredNanos) { HANDLE timer = CreateWaitableTimer(nullptr, true, nullptr); if (timer == nullptr) { throw std::exception("Could not create waitable timer"); } auto state = std::make_unique<State>(timer, nullptr, callback); LARGE_INTEGER dueTime; dueTime.QuadPart = -timeInHundredNanos; if (!SetWaitableTimer(timer, &dueTime, 0, nullptr, nullptr, false)) { throw std::exception("Could not set waitable timer"); } HANDLE waitHandle; if (!RegisterWaitForSingleObject( &waitHandle, timer, [](void* state, unsigned char) { std::unique_ptr<State> callbackState((State*)state); callbackState->m_callback(); }, state.get(), INFINITE, WT_EXECUTEONLYONCE)) { throw std::exception("Could not register wait"); }; state->m_waitHandle = waitHandle; state.release(); } private: class State { public: State(HANDLE timer, HANDLE waitHandle, const T& callback) :m_timer(timer), m_waitHandle(waitHandle), m_callback(callback) { } ~State() { if (m_waitHandle != nullptr) { UnregisterWait(m_waitHandle); } if (m_timer != nullptr) { CloseHandle(m_timer); } } HANDLE m_waitHandle; HANDLE m_timer; T m_callback; }; }; template <class T> void call_after(const T& callback, unsigned int timeInMs) { Timer<T> timer(callback, timeInMs * 10000); } int main(int argc, char* argv[]) { std::function<void()> callback = []{ std::cout << "in callback\n"; }; call_after(callback, 1000); std::cin.get(); }
这是迄今为止的代码:
我正在使用VC ++ 2012(没有variadic模板)
//header #include <thread> #include <mutex> #include <condition_variable> #include <vector> #include <chrono> #include <memory> #include <algorithm> template<class T> class TimerThread { typedef std::chrono::high_resolution_clock clock_t; struct TimerInfo { clock_t::time_point m_TimePoint; T m_User; template <class TArg1> TimerInfo(clock_t::time_point tp, TArg1 && arg1) : m_TimePoint(tp) , m_User(std::forward<TArg1>(arg1)) { } template <class TArg1, class TArg2> TimerInfo(clock_t::time_point tp, TArg1 && arg1, TArg2 && arg2) : m_TimePoint(tp) , m_User(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2)) { } }; std::unique_ptr<std::thread> m_Thread; std::vector<TimerInfo> m_Timers; std::mutex m_Mutex; std::condition_variable m_Condition; bool m_Sort; bool m_Stop; void TimerLoop() { for (;;) { std::unique_lock<std::mutex> lock(m_Mutex); while (!m_Stop && m_Timers.empty()) { m_Condition.wait(lock); } if (m_Stop) { return; } if (m_Sort) { //Sort could be done at insert //but probabily this thread has time to do std::sort(m_Timers.begin(), m_Timers.end(), [](const TimerInfo & ti1, const TimerInfo & ti2) { return ti1.m_TimePoint > ti2.m_TimePoint; }); m_Sort = false; } auto now = clock_t::now(); auto expire = m_Timers.back().m_TimePoint; if (expire > now) //can I take a nap? { auto napTime = expire - now; m_Condition.wait_for(lock, napTime); //check again auto expire = m_Timers.back().m_TimePoint; auto now = clock_t::now(); if (expire <= now) { TimerCall(m_Timers.back().m_User); m_Timers.pop_back(); } } else { TimerCall(m_Timers.back().m_User); m_Timers.pop_back(); } } } template<class T, class TArg1> friend void CreateTimer(TimerThread<T>& timerThread, int ms, TArg1 && arg1); template<class T, class TArg1, class TArg2> friend void CreateTimer(TimerThread<T>& timerThread, int ms, TArg1 && arg1, TArg2 && arg2); public: TimerThread() : m_Stop(false), m_Sort(false) { m_Thread.reset(new std::thread(std::bind(&TimerThread::TimerLoop, this))); } ~TimerThread() { m_Stop = true; m_Condition.notify_all(); m_Thread->join(); } }; template<class T, class TArg1> void CreateTimer(TimerThread<T>& timerThread, int ms, TArg1 && arg1) { { std::unique_lock<std::mutex> lock(timerThread.m_Mutex); timerThread.m_Timers.emplace_back(TimerThread<T>::TimerInfo(TimerThread<T>::clock_t::now() + std::chrono::milliseconds(ms), std::forward<TArg1>(arg1))); timerThread.m_Sort = true; } // wake up timerThread.m_Condition.notify_one(); } template<class T, class TArg1, class TArg2> void CreateTimer(TimerThread<T>& timerThread, int ms, TArg1 && arg1, TArg2 && arg2) { { std::unique_lock<std::mutex> lock(timerThread.m_Mutex); timerThread.m_Timers.emplace_back(TimerThread<T>::TimerInfo(TimerThread<T>::clock_t::now() + std::chrono::milliseconds(ms), std::forward<TArg1>(arg1), std::forward<TArg2>(arg2))); timerThread.m_Sort = true; } // wake up timerThread.m_Condition.notify_one(); } //sample #include <iostream> #include <string> void TimerCall(int i) { std::cout << i << std::endl; } int main() { std::cout << "start" << std::endl; TimerThread<int> timers; CreateTimer(timers, 2000, 1); CreateTimer(timers, 5000, 2); CreateTimer(timers, 100, 3); std::this_thread::sleep_for(std::chrono::seconds(5)); std::cout << "end" << std::endl; }
爱德华的asynchronous解决scheme:
- 创build新的线程
- 睡在那个线程中
- 在该线程中执行任务
很简单,可能只是为你工作。
我也想给一个更高级的版本,它有这些优点:
- 没有线程启动开销
- 每个进程只需要一个额外的线程来处理所有定时任务
这可能在大型软件项目中特别有用,在这些项目中,在进程中重复执行了许多任务,并关心资源使用情况(线程)以及启动开销。
想法:有一个服务线程处理所有注册的定时任务。 使用boost io_service。
代码类似于: http : //www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/tutorial/tuttimer2/src.html
#include <cstdio> #include <boost/asio.hpp> #include <boost/date_time/posix_time/posix_time.hpp> int main() { boost::asio::io_service io; boost::asio::deadline_timer t(io, boost::posix_time::seconds(1)); t.async_wait([](const boost::system::error_code& /*e*/){ printf("Printed after 1s\n"); }); boost::asio::deadline_timer t2(io, boost::posix_time::seconds(1)); t2.async_wait([](const boost::system::error_code& /*e*/){ printf("Printed after 1s\n"); }); // both prints happen at the same time, // but only a single thread is used to handle both timed tasks // - namely the main thread calling io.run(); io.run(); return 0; }