57

C ++ 11を使用してタイマーイベントを作成するにはどうすればよいですか?

「今から1秒後に電話して」のようなものが必要です。

図書館はありますか?

4

6 に答える 6

79

あなたが達成したいことであると私が信じていることの簡単な実装を行いました。later次の引数でクラスを使用できます。

  • int (コードを実行するまで待機するミリ秒)
  • bool (true の場合、即座に戻り、指定された時間後に別のスレッドでコードを実行します)
  • 可変引数 (正確にstd::bindにフィードするもの)

orをさらに高い精度に変更std::chrono::millisecondsし、2 番目の int と for ループを追加して、コードを実行する回数を指定できます。std::chrono::nanosecondsmicroseconds

さあ、お楽しみください:

#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;
}

2 秒後の出力:

101
于 2013-02-02T18:46:57.043 に答える
5

これは私がこれまでに持っているコードです:

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;
}
于 2013-02-04T17:09:00.000 に答える
4

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();
}
于 2015-04-21T04:22:43.927 に答える
1

簡単な解決策を探していますが、見つけたものはすべて長すぎて複雑です。ドキュメントを読んだ後、これはほんの数行のコードで実行できることがわかりました。

この質問は古いかもしれませんが、将来の研究者にとって有益です。

例:スレッドを停止する場合に設定isContinuefalseます。

#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()と、実行メイン スレッドが一時停止し、新しいスレッドが終了するまで待機します。
于 2021-03-12T03:13:23.367 に答える