C ++ Реализация функции Timed Callback

Я хочу реализовать некоторую систему на c ++, чтобы я мог вызвать функцию и запросить другую функцию, которая будет вызвана за X миллисекунд. Что-то вроде этого:

callfunctiontimed(25, funcName);

25 — количество миллисекунд до вызова функции.

Я хотел бы знать, если многопоточность требуется для этого, а затем использовать некоторую функцию задержки? Помимо использования указателя на функцию, как бы эта функция работала?

15

Решение

Для портативного решения вы можете использовать boost :: asio. Ниже приведена демонстрация, которую я написал некоторое время назад.
Ты можешь измениться

t.expires_from_now(boost::posix_time::seconds(1));

для удовлетворения вам нужно, скажем, сделать вызов функции после 200 миллисекунд.

t.expires_from_now(boost::posix_time::milliseconds(200));

Ниже приведен полный рабочий пример. Он звонит многократно, но я думаю, что это будет легко позвонить только один раз, просто немного изменив.

#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

using namespace boost::asio;
using namespace std;

class Deadline
{
public:
Deadline(deadline_timer &timer) : t(timer) {
wait();
}

void timeout(const boost::system::error_code &e) {
if (e)
return;
cout << "tick" << endl;
wait();
}

void cancel() {
t.cancel();
}private:
void wait() {
t.expires_from_now(boost::posix_time::seconds(1)); //repeat rate here
t.async_wait(boost::bind(&Deadline::timeout, this, boost::asio::placeholders::error));
}

deadline_timer &t;
};class CancelDeadline {
public:
CancelDeadline(Deadline &d) :dl(d) { }
void operator()() {
string cancel;
cin >> cancel;
dl.cancel();
return;
}
private:
Deadline &dl;
};int main()
{
io_service io;
deadline_timer t(io);
Deadline d(t);
CancelDeadline cd(d);
boost::thread thr1(cd);
io.run();
return 0;
}//result:
//it keeps printing tick every second until you enter cancel and enter in the console
tick
tick
tick
17

Другие решения

Многие люди предоставили здесь хорошие ответы на этот вопрос, но я коснусь этого вопроса напрямую, потому что у меня была похожая проблема пару лет назад. Я не мог использовать Boost по нескольким причинам — я знаю, что Boost отлично используется во многих программах с открытым исходным кодом. Более того, я очень хотел Понимаю таймеры и обратные вызовы, особенно в отношении сред на базе Linux. Итак, я написал свой.

Принципиально у меня есть Timer класс и TimerCallback учебный класс. Типичный обратный вызов, реализованный как унаследованный класс TimerCallback класс, поместит операции, которые будут выполнены при обратном вызове в triggered () метод, реализованный специально для нужд.

В соответствии с обычной семантикой, Timer Объект связан с объектом обратного вызова, который предположительно содержит всю необходимую информацию, необходимую для выполнения обратного вызова. Планирование таймера управляется одним minheap таймера в масштабах всей среды, который должен поддерживаться в отдельном потоке / процессе. Эта задача minheap делает только одно: она минимизирует minheap событий обратного вызова, установленных в будущем. Minheap выбирает следующее событие для запуска O(1) и может minheapify оставшиеся в O(log n) за n таймер событий. Он также может вставить новое событие таймера в O(log n) (Прочитайте нежное введение к кучам Вот).

Когда срабатывает таймер, планировщик minheap проверяет, является ли он периодическим таймером, таймером одного выстрела или таймером, который будет выполняться определенное количество раз. Соответственно, объект таймера либо удаляется из minheap, либо снова вставляется обратно в minheap со следующим временем выполнения. Если объект таймера должен быть удален, то он удаляется из minheap (но удаление объекта таймера может или не может быть оставлено для задачи, которая его создала), а остальная часть кучи — minheap-ified; т. е. переставлены для удовлетворения свойства minheap.

Работающая и модульно проверенная реализация Вот, и может содержать ошибки (взятые из моего приложения), но я подумал, что это может кому-то помочь. Реализация многопроцессная (fork()ed-process) на основе (а также использует pthreads в основной задаче (процессе)) и использует общую память POSIX и очереди сообщений POSIX для связи между процессами.

5

Вы хотите сделать это асинхронным, чтобы обратный вызов выполнялся по истечении 25 миллисекунд, не блокируя основной исполняющий поток? Если это так, вы можете выполнить обратный вызов в отдельном потоке от функции обратного вызова таймера / таймера, которую вы реализуете.

Если вы не используете многопоточность, то ваша основная или вызывающая функция
callfunctiontimed (25, funcName); будет блокировать во время сна / уснуть. Это твой выбор
Теперь о том, какое поведение вы хотите реализовать.

Реальное решение не будет таким простым, как многопоточность или нет. Есть такие вещи, как, как вы храните информацию о разных таймерах / обратных вызовах, учитывая, что функция может вызываться несколько раз с разными таймаутами и функциями.

Один из способов сделать это будет выглядеть так:

  1. Создайте отсортированный список таймеров / обратных вызовов, отсортированный по времени истечения.
  2. Имейте в основном потоке и один поток, который смотрит на обратные вызовы / таймеры, назовите это потоком таймера
  3. Когда новый обратный вызов добавлен, добавьте его в отсортированный список.
  4. Поток таймера может быть инициализирован для ожидания наименьшего количества времени в отсортированном списке или заголовке. Повторно инициализируйте его по мере добавления новых обратных вызовов. Там будет некоторая математика и условия, чтобы позаботиться.
  5. Когда поток таймера находится в спящем режиме, он удаляет и просматривает заголовок списка и выполняет указатель функции в новом потоке. Поток таймера повторно инициализируется со временем ожидания нового заголовка списка.

    main() {
    //spawn a timer thread with pthread create
    
    callfunctiontimed(25, test);
    callfunctiontimed(35, show);
    callfunctiontimed(4,  print);
    }
    
    callfunctionTImed(int time, (func*)function, void*data) //
    {
    //add information to sorted list of timer and callbacks
    //re-initialize sleep_time for timer thread if needed.
    return.
    }
    timerThread() {
    while(1){
    sleep(sleep_time);
    //look at head of timer list, remove it, call function in a new thread
    //adjust sleep time as per new head
    }
    }
    

Надеюсь, это дает представление о том, что я имел в виду, хотя это не идеально и имеет несколько проблем.

5

В окнах у вас есть SetTimerhttp://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

Образец кода:

#define STRICT 1
#include <windows.h>
#include <iostream.h>

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{cout << "CALLBACK " << dwTime << '\n';
cout.flush();
}

int main(int argc, char *argv[], char *envp[])
{
int Counter=0;
MSG Msg;

UINT TimerId = SetTimer(NULL, 0, 2000, &TimerProc); //2000 milliseconds

cout << "TimerId: " << TimerId << '\n';
if (!TimerId)
return 16;

while (GetMessage(&Msg, NULL, 0, 0))
{
++Counter;
if (Msg.message == WM_TIMER)
cout << "Counter: " << Counter << "; timer message\n";
else
cout << "Counter: " << Counter << "; message: " << Msg.message << '\n';
DispatchMessage(&Msg);
}

KillTimer(NULL, TimerId);
return 0;
}
2
По вопросам рекламы [email protected]