如何使用 C++ 11 创建计时器事件?
我需要类似:“从现在起 1 秒后给我打电话”。
有图书馆吗?
对我认为您想要实现的目标进行了简单的实现。您可以使用later
具有以下参数的类:
您可以更改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
Edward 的异步解决方案:
很简单,可能只适合你。
我还想提供一个更高级的版本,它具有以下优点:
这在大型软件项目中可能特别有用,在这些项目中,您在流程中重复执行许多任务并且您关心资源使用(线程)以及启动开销。
想法:拥有一个服务线程来处理所有已注册的定时任务。为此使用 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;
}
使用RxCpp ,
std::cout << "Waiting..." << std::endl;
auto values = rxcpp::observable<>::timer<>(std::chrono::seconds(1));
values.subscribe([](int v) {std::cout << "Called after 1s." << std::endl;});
这是我到目前为止的代码:
我正在使用 VC++ 2012(没有可变参数模板)
//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;
}
如果您在 Windows 上,则可以使用CreateThreadpoolTimer函数来安排回调,而无需担心线程管理并且不会阻塞当前线程。
template<typename T>
static void __stdcall timer_fired(PTP_CALLBACK_INSTANCE, PVOID context, PTP_TIMER timer)
{
CloseThreadpoolTimer(timer);
std::unique_ptr<T> callable(reinterpret_cast<T*>(context));
(*callable)();
}
template <typename T>
void call_after(T callable, long long delayInMs)
{
auto state = std::make_unique<T>(std::move(callable));
auto timer = CreateThreadpoolTimer(timer_fired<T>, state.get(), nullptr);
if (!timer)
{
throw std::runtime_error("Timer");
}
ULARGE_INTEGER due;
due.QuadPart = static_cast<ULONGLONG>(-(delayInMs * 10000LL));
FILETIME ft;
ft.dwHighDateTime = due.HighPart;
ft.dwLowDateTime = due.LowPart;
SetThreadpoolTimer(timer, &ft, 0 /*msPeriod*/, 0 /*msWindowLength*/);
state.release();
}
int main()
{
auto callback = []
{
std::cout << "in callback\n";
};
call_after(callback, 1000);
std::cin.get();
}
我正在寻找一个简单的解决方案,但我发现的一切都太长太复杂了。阅读文档后,我发现只需几行代码即可完成。
这个问题可能很老,但对未来的研究人员可能是有益的。
示例:如果要停止线程,请设置isContinue
为。false
#include <chrono>
#include <thread>
volatile bool isContinue = true;
void NameOfYourFunction(){
while(continue){
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //sleep for 1 seconds
//do something here after every 1 seconds...
}
}
int main(){
std::thread your_thread(NameOfYourFunction); // Register your `YourFunction`.
your_thread.detach(); // this will be non-blocking thread.
//your_thread.join(); // this will be blocking thread.
}
使用detach()
或join()
根据您的情况。
detach()
时,执行主线程继续运行。join()
时,执行主线程暂停并等待,直到新线程结束。