So I have print function that I want to execute in 5 seconds. The Problem is that I want everything else in the function. So For example if my code is:
// insert code here...
printf("(5 seconds later) Hello"); /* should be executed in 5 seconds */
printf("heya");
In the main function for example. Now here's the tricky part. While the first line should be executed in 5 seconds, the second line should be executed just like normal if the first line wasn't there at all. So the output would be:
heya
(5 seconds later) Hello
If you familiar with Cocoa or Cocoa Touch, this is exactly how the NSTimer Class works. Using C++, is there a simpler or built in way other than using a thread? If not, how would I go about doing this using multi-threading?
Using <chrono>
and <thread>
, you can create a pretty rudimentary, but easy one:
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
Another method, which Pubby points out, and has the advantage of automatically waiting for the thread to finish and not stopping if an exception is thrown, is to use 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");
The result of std::async
being stored into a variable means the call will start a new thread to run the function in. If you don't store the result, no new thread. It's one of those new gotchas in the language.
Note that it might not be precisely five seconds later when it prints, and there's no syncing of the output, so you might get interleaved output blocks (printf
is atomic, so the entire output of each call would interleave) if printing more than just a single thing in each thread. Without synchronization, there's no guarantee of which statements happen when, so care should be taken if you do need to be aware of synchronization issues that can arise. For basic purposes, this should work, though.
Here's how I've solved this problem:
#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;
}
My snap version with boost asio and std::async. No sleeps employed.
#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;
}