创建一个计时器在X秒内调用一个函数

Create a Timer to call a function in X Seconds

本文关键字:一个 调用 函数 计时器 创建      更新时间:2023-10-16

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

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

以main函数为例。现在是棘手的部分。虽然第一行应该在5秒内执行,但如果第一行根本不存在,第二行应该像正常一样执行。因此输出将是:

heya
(5 seconds later) Hello

如果你熟悉Cocoa或Cocoa Touch,这就是NSTimer类的工作方式。使用c++,有没有比使用线程更简单或内置的方法?如果没有,我该如何使用多线程来实现这一点呢?

使用<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存储到变量中的结果意味着调用将启动一个新线程来运行该函数。如果不存储结果,就不会有新的线程。这是语言中的一个新问题。

注意,如果在每个线程中打印不止一个东西,那么它可能不会精确地在5秒后打印,并且没有同步输出,因此您可能会得到交错的输出块(printf是原子的,因此每个调用的整个输出将交错)。如果没有同步,就不能保证哪些语句在什么时候发生,因此如果您确实需要注意可能出现的同步问题,就应该小心。但是,对于基本目的,这应该可以工作。

我是这样解决这个问题的:

#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("%in", myBool());
    printf("heyan");
    // 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;
}

我的snap版本与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;
}