Как создать события таймера с помощью С++ 11?
Мне нужно что-то вроде: "Позвони мне через 1 секунду".
Есть ли библиотека?
Как создать события таймера с помощью С++ 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
Если вы находитесь в Windows, вы можете использовать класс concurrency:: timer для планирования обратного вызова без необходимости беспокоиться о управлении потоками и без блокировки текущей нити.
#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();
}
Также проверьте эту статью.
Если вы являетесь чистым энтузиастом окон или не предпочитаете использовать ppl, вы можете использовать CreateWaitableTimer и RegisterWaitForSingleObject, чтобы запланировать обратный вызов по умолчанию в потоке по умолчанию.
#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();
}
Это код, который у меня есть до сих пор:
Я использую VС++ 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;
}
Асинхронное решение от 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;
}