创建一个Timer以在X秒内调用一个函数

时间:2013-04-03 01:44:32

标签: c++ c++11 timer

所以我有打印功能,我想在5秒内执行。问题是我想要函数中的其他所有东西。所以例如,如果我的代码是:

// insert code here...
printf("(5 seconds later) Hello"); /* should be executed in 5 seconds */
printf("heya");

以主要功能为例。现在这里是棘手的部分。虽然第一行应该在5秒内执行,但第二行应该像正常情况一样执行,如果第一行根本不存在的话。所以输出将是:

heya
(5 seconds later) Hello

如果您熟悉Cocoa或Cocoa Touch,这正是NSTimer类的工作原理。使用C ++,除了使用线程之外,还有更简单或内置的方法吗?如果没有,我将如何使用多线程进行此操作?

3 个答案:

答案 0 :(得分:4)

使用<chrono><thread>,您可以创建一个非常简单但又简单的基础:

std::thread printLater{[] {
    std::this_thread::sleep_for(std::chrono::seconds(5));
    printf("(5 seconds later) Hello");
}};

printf("heya");

printLater.join(); //when you want to wait for the thread to complete

Pubby指出的另一种方法是使用std::async

,它具有自动等待线程完成而不会在抛出异常时停止的优点。
auto f = std::async(std::launch::async, [] {
    std::this_thread::sleep_for(std::chrono::seconds(5));
    printf("(5 seconds later) Hello");
});

printf("heya");

std::async存储到变量中的结果意味着调用将启动一个新线程来运行该函数。如果不存储结果,则不会有新线程。这是该语言中的新问题之一。

请注意,打印时可能不会恰好五秒钟,并且输出没有同步,因此您可能会得到交错输出块(printf是原子的,因此每次调用的整个输出都会交错)如果在每个线程中打印的不仅仅是一件事。如果没有同步,则无法保证何时发生语句,因此如果您确实需要了解可能出现的同步问题,请务必小心。出于基本目的,这应该可行。

答案 1 :(得分:1)

以下是我解决这个问题的方法:

#include <iostream>
#include <thread>
#include <chrono>

std::thread timerThread;

void printStatement() {
    std::this_thread::sleep_for(std::chrono::seconds(5));
    printf("(5 seconds later) Hello");
}

bool myBool() {
    timerThread = std::thread(printStatement);
    return YES;
}


int main(int argc, const char * argv[])
{
    // insert code here...
    printf("%i\n", myBool());
    printf("heya\n");
    // you could also use the async stuff, join or std::future instead of sleep()
    sleep(5); // this is only here to keep the thread from being detatched before it can even finish sleeping
    timerThread.detach();
    return 0;
}

答案 2 :(得分:0)

我的快照版本有boost asio和std :: async。没有睡觉。

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/noncopyable.hpp>

#include <chrono>
#include <future>
#include <memory>
#include <iostream>

class MonotonicExecutor
    : public boost::noncopyable,
      public std::enable_shared_from_this<MonotonicExecutor> {
  typedef std::function<void()> Functor;

public:
  MonotonicExecutor(boost::posix_time::time_duration trig)
      : m_service(),
        m_serviceWork(
            std::make_shared<boost::asio::io_service::work>(m_service)),
        m_deadlineTimer(m_service), m_trigger(trig) {
    auto fut = std::async(std::launch::async, [&]() { m_service.run(); });
    fut.wait_for(std::chrono::milliseconds(1));
  }
  void executeAsync(Functor fun) {
    m_deadlineTimer.expires_from_now(m_trigger);
    m_deadlineTimer.async_wait(std::bind(&MonotonicExecutor::execute,
                                         shared_from_this(),
                                         std::placeholders::_1, fun));
  }
  void abort() { m_deadlineTimer.cancel(); }

private:
  void execute(const boost::system::error_code &err, Functor fun) {
    if (err != boost::asio::error::operation_aborted &&
        m_deadlineTimer.expires_at() <=
            boost::asio::deadline_timer::traits_type::now()) {
      m_deadlineTimer.cancel();
      fun();
      m_deadlineTimer.expires_from_now(m_trigger);
      m_deadlineTimer.async_wait(std::bind(&MonotonicExecutor::execute,
                                           shared_from_this(),
                                           std::placeholders::_1, fun));
    }
  }

private:
  boost::asio::io_service m_service;
  std::shared_ptr<boost::asio::io_service::work> m_serviceWork;
  boost::asio::deadline_timer m_deadlineTimer;
  boost::posix_time::time_duration m_trigger;
};

int main(int argc, char *argv[]) {
  auto executor =
      std::make_shared<MonotonicExecutor>(boost::posix_time::seconds(3));
  executor->executeAsync([&]() {
    std::cout << boost::posix_time::to_iso_string(
                     boost::posix_time::second_clock::local_time())
              << std::endl;
  });

  auto stop = std::chrono::system_clock::now() + std::chrono::seconds(30);
  while (std::chrono::system_clock::now() < stop) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
  }
  executor->abort();
  std::cout << "Wait and see if the task is aborted" << std::endl;
  stop = std::chrono::system_clock::now() + std::chrono::seconds(30);
  while (std::chrono::system_clock::now() < stop) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
  }
  return 0;
}