I require a heartbeat signal every 10 seconds or so. To implement this I have produced a class with the following constructor:
HeartBeat::HeartBeat (int Seconds, MessageQueue * MsgQueue)
{
TimerSeconds = Seconds;
pQueue = MsgQueue;
isRunning = true;
assert(!m_pHBThread);
m_pHBThread = shared_ptr<thread>(new thread(boost::bind(&HeartBeat::TimerStart,this)));
}
Which calls the following method in a new thread:
void HeartBeat::TimerStart ()
{
while (1)
{
cout << "heartbeat..." << endl;
boost::this_thread::sleep(boost::posix_time::seconds (TimerSeconds));
addHeartBeat();
}
}
This produces a heartbeat with out any issues. However I would like to be able to reset the sleep timer back to zero. Is there a simple way of doing this, or should I use something other than
boost::this_thread::sleep
for my sleep?
OS: Redhat
IDE: Eclipse
Code language: C++
EDIT:
I have looked at using
m_pHBThread->interrupt();
And it seems to be what I'm after, so thank you!
This sounds exactly like what asynchronous timer does. Since you're using boost already, perhaps it makes sense to use boost's own async timers in the long run?
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include <boost/asio.hpp>
boost::posix_time::ptime now()
{
return boost::posix_time::microsec_clock::local_time();
}
class HeartBeat {
boost::asio::io_service ios;
boost::asio::deadline_timer timer;
boost::posix_time::time_duration TimerSeconds;
boost::thread thread;
public:
HeartBeat(int Seconds) : ios(), timer(ios),
TimerSeconds(boost::posix_time::seconds(Seconds))
{
reset(); // has to start timer before starting the thread
thread = boost::thread(boost::bind(&boost::asio::io_service::run,
&ios));
}
~HeartBeat() {
ios.stop();
thread.join();
}
void reset()
{
timer.expires_from_now(TimerSeconds);
timer.async_wait(boost::bind(&HeartBeat::TimerExpired,
this, boost::asio::placeholders::error));
}
void TimerExpired(const boost::system::error_code& ec)
{
if (ec == boost::asio::error::operation_aborted) {
std::cout << "[" << now() << "] timer was reset" << std::endl;
} else {
std::cout << "[" << now() << "] heartbeat..." << std::endl;
reset();
}
}
};
int main()
{
std::cout << "[" << now() << "] starting up.\n";
HeartBeat hb(10);
sleep(15);
std::cout << "[" << now() << "] Resetting the timer\n";
hb.reset();
sleep(15);
}
test run:
~ $ ./test
[2011-Sep-07 12:08:17.348625] starting up.
[2011-Sep-07 12:08:27.348944] heartbeat...
[2011-Sep-07 12:08:32.349002] Resetting the timer
[2011-Sep-07 12:08:32.349108] timer was reset
[2011-Sep-07 12:08:42.349160] heartbeat...
Perhaps you can use interrupt() to do this.
Well, it is not very efficient to launch a new thread every time you have an heart beat...
I'd do it instead with a single thread and a sleep inside it.
If you need to change the heart beat frequency then you can kill the current thread and start a new one with a new sleep time. You can use the boost::thread and the interrupt signal for this.
EDIT: look here for info on boost threads: boost thread management
if you want to reset the time to zero and execute your code immediately then call it inside the catch for boost::thread_interrupted...
EDIT2: I didn't look properly to the code and I assumed that the common error of launching a new thread for each heart beat was there... sorry, my mistake... I guess I don't like the fact that the thread's name is: TimerStart()
Anyway I think that using the interrupt() and catching it should work if you need to execute the heart beat right away.
Related
I'm studying concurrency in C++ and I'm trying to implement a multithreaded callback registration system. I came up with the following code, which is supposed to accept registration requests until an event occurs. After that, it should execute all the registered callbacks in order with which they were registered. The registration order doesn't have to be deterministic.
The code doesn't work as expected. First of all, it rarely prints the "Pushing callback with id" message. Secondly, it sometimes hangs (a deadlock caused by a race condition, I assume). I'd appreciate help in figuring out what's going on here. If you see that I overcomplicate some parts of the code or misuse some pieces, please also point it out.
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
class CallbackRegistrar{
public:
void registerCallbackAndExecute(std::function<void()> callback) {
if (!eventTriggered) {
std::unique_lock<std::mutex> lock(callbackMutex);
auto saved_id = callback_id;
std::cout << "Pushing callback with id " << saved_id << std::endl;
registeredCallbacks.push(std::make_pair(callback_id, callback));
++callback_id;
callbackCond.wait(lock, [this, saved_id]{return releasedCallback.first == saved_id;});
releasedCallback.second();
callbackExecuted = true;
eventCond.notify_one();
}
else {
callback();
}
}
void registerEvent() {
eventTriggered = true;
while (!registeredCallbacks.empty()) {
releasedCallback = registeredCallbacks.front();
callbackCond.notify_all();
std::unique_lock<std::mutex> lock(eventMutex);
eventCond.wait(lock, [this]{return callbackExecuted;});
callbackExecuted = false;
registeredCallbacks.pop();
}
}
private:
std::queue<std::pair<unsigned, std::function<void()>>> registeredCallbacks;
bool eventTriggered{false};
bool callbackExecuted{false};
std::mutex callbackMutex;
std::mutex eventMutex;
std::condition_variable callbackCond;
std::condition_variable eventCond;
unsigned callback_id{1};
std::pair<unsigned, std::function<void()>> releasedCallback;
};
int main()
{
CallbackRegistrar registrar;
std::thread t1(&CallbackRegistrar::registerCallbackAndExecute, std::ref(registrar), []{std::cout << "First!\n";});
std::thread t2(&CallbackRegistrar::registerCallbackAndExecute, std::ref(registrar), []{std::cout << "Second!\n";});
registrar.registerEvent();
t1.join();
t2.join();
return 0;
}
This answer has been edited in response to more information being provided by the OP in a comment, the edit is at the bottom of the answer.
Along with the excellent suggestions in the comments, the main problem that I have found in your code is with the callbackCond condition variable wait condition that you have set up. What happens if releasedCallback.first does not equal savedId?
When I have run your code (with a thread-safe queue and eventTriggered as an atomic) I found that the problem was in this wait function, if you put a print statement in that function you will find that you get something like this:
releasedCallback.first: 0, savedId: 1
This then waits forever.
In fact, I've found that the condition variables used in your code aren't actually needed. You only need one, and it can live inside the thread-safe queue that you are going to build after some searching ;)
After you have the thread-safe queue, the code from above can be reduced to:
class CallbackRegistrar{
public:
using NumberedCallback = std::pair<unsigned int, std::function<void()>>;
void postCallback(std::function<void()> callback) {
if (!eventTriggered)
{
std::unique_lock<std::mutex> lock(mutex);
auto saved_id = callback_id;
std::cout << "Pushing callback with id " << saved_id << std::endl;
registeredCallbacks.push(std::make_pair(callback_id, callback));
++callback_id;
}
else
{
while (!registeredCallbacks.empty())
{
NumberedCallback releasedCallback;
registeredCallbacks.waitAndPop(releasedCallback);
releasedCallback.second();
}
callback();
}
}
void registerEvent() {
eventTriggered = true;
}
private:
ThreadSafeQueue<NumberedCallback> registeredCallbacks;
std::atomic<bool> eventTriggered{false};
std::mutex mutex;
unsigned int callback_id{1};
};
int main()
{
CallbackRegistrar registrar;
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++)
{
threads.push_back(std::thread(&CallbackRegistrar::postCallback,
std::ref(registrar),
[i]{std::cout << std::to_string(i) <<"\n";}
));
}
registrar.registerEvent();
for (auto& thread : threads)
{
thread.join();
}
return 0;
}
I'm not sure if this does exactly what you want, but it doesn't deadlock. It's a good starting point in any case, but you need to bring your own implementation of ThreadSafeQueue.
Edit
This edit is in response to the comment by the OP stating that "once the event occurs, all the callbacks should be executed in [the] order that they've been pushed to the queue and by the same thread that registered them".
This was not mentioned in the original question post. However, if that is the required behaviour then we need to have a condition variable wait in the postCallback method. I think this is also the reason why the OP had the condition variable in the postCallback method in the first place.
In the code below I have made a few edits to the callbacks, they now take input parameters. I did this to print some useful information while the code is running so that it is easier to see how it works, and, importantly how the condition variable wait is working.
The basic idea is similar to what you had done, I've just trimmed out the stuff you didn't need.
class CallbackRegistrar{
public:
using NumberedCallback = std::pair<unsigned int, std::function<void(int, int)>>;
void postCallback(std::function<void(int, int)> callback, int threadId) {
if (!m_eventTriggered)
{
// Lock the m_mutex
std::unique_lock<std::mutex> lock(m_mutex);
// Save the current callback ID and push the callback to the queue
auto savedId = m_currentCallbackId++;
std::cout << "Pushing callback with ID " << savedId << "\n";
m_registeredCallbacks.push(std::make_pair(savedId, callback));
// Wait until our thread's callback is next in the queue,
// this will occur when the ID of the last called callback is one less than our saved callback.
m_conditionVariable.wait(lock, [this, savedId, threadId] () -> bool
{
std::cout << "Waiting on thread " << threadId << " last: " << m_lastCalledCallbackId << ", saved - 1: " << (savedId - 1) << "\n";
return (m_lastCalledCallbackId == (savedId - 1));
});
// Once we are finished waiting, get the callback out of the queue
NumberedCallback retrievedCallback;
m_registeredCallbacks.waitAndPop(retrievedCallback);
// Update last callback ID and call the callback
m_lastCalledCallbackId = retrievedCallback.first;
retrievedCallback.second(m_lastCalledCallbackId, threadId);
// Notify one waiting thread
m_conditionVariable.notify_one();
}
else
{
// If the event is already triggered, call the callback straight away
callback(-1, threadId);
}
}
void registerEvent() {
// This is all we have to do here.
m_eventTriggered = true;
}
private:
ThreadSafeQueue<NumberedCallback> m_registeredCallbacks;
std::atomic<bool> m_eventTriggered{ false};
std::mutex m_mutex;
std::condition_variable m_conditionVariable;
unsigned int m_currentCallbackId{ 1};
std::atomic<unsigned int> m_lastCalledCallbackId{ 0};
};
The main function is as above, except I am creating 100 threads instead of 10, and I have made the callback print out information about how it was called.
for (int createdThreadId = 0; createdThreadId < 100; createdThreadId++)
{
threads.push_back(std::thread(&CallbackRegistrar::postCallback,
std::ref(registrar),
[createdThreadId](int registeredCallbackId, int callingThreadId)
{
if (registeredCallbackId < 0)
{
std::cout << "Callback " << createdThreadId;
std::cout << " called immediately, from thread: " << callingThreadId << "\n";
}
else
{
std::cout << "Callback " << createdThreadId;
std::cout << " called from thread " << callingThreadId;
std::cout << " after being registered as " << registeredCallbackId << "\n";
}
},
createdThreadId));
}
I am not entirely sure why you want to do this, as it seems to defeat the point of having multiple threads, although I may be missing something there. But, regardless, I hope this helps you to understand better the problem you are trying to solve.
Experimenting with this code some more, I found out why the "Pushing callback with id " part was rarely printed. It's because the call to registrar.registerEvent from the main thread was usually faster than the calls to registerCallbackAndExecute from separate threads. Because of that, the condition if (!eventTriggered) was almost never fulfilled (eventTriggered had been set to true in the registerEvent method) and hence all calls to registerCallbackAndExecute were falling into the else branch and executing straightaway.
Then, the program sometimes also didn't finish, because of a race condition between registerEvent and registerCallbackAndExecute. Sometimes, registerEvent was being called after the check if (!eventTriggered) but before pushing the callback to the queue. Then, registerEvent completed instantly (as the queue was empty) while the thread calling registerCallbackAndExecute was pushing the callback to the queue. The latter thread then kept waiting forever for the event (that had already happened) to happen.
Currently I'm working on server development for an online game and decided to implement it as multithreaded application.
I have a main thread which implements while loop which abstractly gets data from the socket.
std::vector<std::thread> games_threads;
int start(int game_id) {
std::this_thread::sleep_for(std::chrono::seconds(10));
return end(game_id);
}
int end(int game_id) {
// some other conditions for turn end
return start(game_id);
}
int main() {
// socket implmementation
while(1) {
Message msg = socket.get_data();
switch(msg->action) {
case GAME_START:
std::thread game_thread(start, create_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
case TURN_END:
std::thread game_thread(end, msg->get_game());
game_thread.detach();
games_threads.push_back(game_thread);
break;
}
}
}
Game creates with turn start() method. And then after waiting 10 secs in call end() method which implements turn end.
After than turn end() method calls start().
But I need also implement force turn end method so I have race condition with 2 cases:
Start -> End normal workflow with 10s timeout (which makes game
thread unavailable for 10 secs)
Forced turn end command (TURN_END).
So I need somehow end the current game thread and replace with one user thread. Or just catch signals somehow with conditional variable but I have already freeze for 10sec and as far as I know I can't wait both things at the same time (conditional variable and sleep ending).
Maybe multithreading is not a good solution at all. Please share your approach in this case.
Thanks
Its not so much that multi-threading is a bad approach as your specific implementation is not right.
A call to the start() function or end() function will never return because they each call each other in a never ending recursion. This is already bad since your stack will be filling up as you enter deeper into function calls.
But that aside, your main loop starts a new thread when you call GAME_START and this new thread goes into its "forever" start()<-->end() loop. "OK" so far, but then when the TURN_END is called your main loop calls end() directly and therefore your main loop also now enters a forever start()<-->end() loop. This now means both your main and your "worker" thread are locked up in these loops that don't return - so no more messages can be processed from your socket.
I would suggest that your main loop uses a condition variable to signal your worker loop to force a new turn.
I am not quite sure what to suggest to replace your start()<-->end() recursion loop because its not clear to me what this is trying to achieve. But possibly a timer class might work here (the example is the first one I found in google)
Complete Example Using Stdin
Here the start function implements a thread loop instead of calling end/start repeatedly... Also the game ID 1 gets ended when you enter end the other games continue as normal. All games exit when you enter exit
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
std::vector<std::thread> games_threads;
std::condition_variable cv;
std::mutex cv_m;
int the_game_id = 0;
int start(int id) {
int game_id = id;
bool running = true;
while (running)
{
std::unique_lock<std::mutex> lk(cv_m);
auto now = std::chrono::system_clock::now();
std::cout << "THREAD " << game_id << ": Waiting for turn..." << std::endl;
// Wait for the signal to end turn only if the game ID is for us.
if(cv.wait_until(lk, now + std::chrono::seconds(10), [&game_id](){return (the_game_id == game_id || the_game_id == -1);}))
{
// Condition var signalled
if (the_game_id == -1)
{
std::cout << "THREAD" << game_id << ": end game - exit" << std::endl;
running = false;
}
else
{
std::cout << "THREAD" << game_id << ": turn end forced" << std::endl;
// Reset the game ID so we don't keep triggering
the_game_id = 0;
}
}
else
{
// 10 second timeout occured
std::cout << "THREAD" << game_id << ": 10 seconds is up, end turn" << std::endl;
}
}
std::cout << "THREAD" << game_id << ": ended" << std::endl;
return 1;
}
int main() {
// pretend socket implmementation - using stdin
int id = 1;
bool done = false;
while(!done) {
std::string cmd;
std::getline(std::cin, cmd);
if (cmd == "start")
{
std::cout << "starting..." << std::endl;
games_threads.push_back({ std::thread( [&id](){ return start(id++); } ) });
}
else if (cmd == "end")
{
std::cout << "ending..." << std::endl;
// Notify game ID 1 to end turn - (but in reality get the ID from the message)
the_game_id = 1;
cv.notify_all();
}
else if (cmd == "exit")
{
std::cout << "exiting all threads..." << std::endl;
// Notify game ID 1 to end turn
the_game_id = -1;
cv.notify_all();
done = true;
}
}
// Tidyup threads
for (auto &th : games_threads)
{
if (th.joinable())
{
th.join();
}
}
}
Output:
> start
starting...
THREAD 1: Waiting for turn...
> start
starting...
THREAD 2: Waiting for turn...
> start
starting...
THREAD 3: Waiting for turn...
> end
ending...
THREAD1: turn end forced
THREAD 1: Waiting for turn...
THREAD2: 10 seconds is up, end turn
THREAD 2: Waiting for turn...
THREAD3: 10 seconds is up, end turn
THREAD 3: Waiting for turn...
THREAD1: 10 seconds is up, end turn
THREAD 1: Waiting for turn...
> exit
exiting all threads...
THREAD1: end game - exit
THREAD1: ended
THREAD2: end game - exit
THREAD2: ended
THREAD3: end game - exit
THREAD3: ended
I'm working on some comms code for which I need a regular timer for monitoring. I'm using boost ASIO for the comms so I decided to use a deadline timer for the timing and put it on the same IO service.
Everything works great the first time the code is run but it goes wrong once the comms (in my case a serial port) is stopped and restarted. The timer begins to malfunction and the comms break down. I believe the two are related so I'm just focusing on the timer for this question.
Consider the code below. This should start a timer and let it run for 10 seconds, stop the timer, and then start it again for another 10 seconds. What actually happens though is that when the timer is restarted it fires continuously, ie without any delay between firing.
#include <iostream>
#include <thread>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
boost::posix_time::ptime timer_start_;
void CallbackTimerFunc(boost::asio::deadline_timer* timer) {
auto time_since_start = timer->expires_at() - timer_start_;
std::cout << "It's been " << time_since_start.total_seconds() << " seconds." << std::endl;
// Sleep is here to prevent spamming when timer starts malfunctioning.
usleep(20000);
timer->expires_at(timer->expires_at() + boost::posix_time::milliseconds(1000));
timer->async_wait(boost::bind(&CallbackTimerFunc, timer));
}
int main(int /*argc*/, char** /*args*/) {
// Start
boost::asio::io_service io_service_;
boost::asio::deadline_timer deadline_timer_(io_service_);
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(&CallbackTimerFunc, &deadline_timer_));
std::thread io_thread_(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
std::cout << "******************************" << std::endl;
// Restart
io_service_.restart();
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(&CallbackTimerFunc, &deadline_timer_));
io_thread_ = std::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
return 0;
}
Expected output is for the timer to count to 10 (well in reality from 0 to 8) twice. The actual output is that it counts to 10 once, and then just goes haywire claiming that hundreds of seconds are passing.
I can make this code work by creating a brand new IO service and timer but that seems like it should be unnecessary given that they are supposed to be reusable.
If anyone can tell me what's going on here or at least reproduce my results I'd appreciate it.
Thanks to #tkausl for putting me on the right track. Here is the corrected code. Note the extra check at the top of CallbackTimerFunc.
#include <iostream>
#include <thread>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
boost::posix_time::ptime timer_start_;
void CallbackTimerFunc(const boost::system::error_code& error, boost::asio::deadline_timer* timer) {
if (error.value() == boost::asio::error::operation_aborted) {
std::cout << "Abort was sent on the first firing. Because of course it would be. Ignoring it will fix the problem. Because of course it will." << std::endl;
return;
}
auto time_since_start = timer->expires_at() - timer_start_;
std::cout << "It's been " << time_since_start.total_seconds() << " seconds." << std::endl;
// Sleep is here to prevent spamming when timer starts malfunctioning.
usleep(20000);
timer->expires_at(timer->expires_at() + boost::posix_time::milliseconds(1000));
timer->async_wait(boost::bind(&CallbackTimerFunc, boost::asio::placeholders::error, timer));
}
int main(int /*argc*/, char** /*args*/) {
// Start
boost::asio::io_service io_service_;
boost::asio::deadline_timer deadline_timer_(io_service_);
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(CallbackTimerFunc, boost::asio::placeholders::error, &deadline_timer_));
std::thread io_thread_(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
std::cout << "******************************" << std::endl;
// Restart
io_service_.restart();
deadline_timer_.expires_from_now(boost::posix_time::milliseconds(1000));
timer_start_ = deadline_timer_.expires_at();
deadline_timer_.async_wait(boost::bind(CallbackTimerFunc, boost::asio::placeholders::error, &deadline_timer_));
io_thread_ = std::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
// Stop
sleep(10);
io_service_.stop();
while (!io_service_.stopped()) usleep(10000);
deadline_timer_.cancel();
io_thread_.join();
return 0;
}
I was learning boost asio documentation.I came across this deadline_timer example.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
/*This timer example shows a timer that fires once every second.*/
void print(const boost::system::error_code& e, boost::asio::deadline_timer* t, int* count)
{
if (*count < 5)
{
std::cout << *count << std::endl;
++(*count);
t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
t->async_wait(boost::bind(print,boost::asio::placeholders::error, t, count));
}
}
int main()
{
boost::asio::io_service io;
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
auto myfunc = boost::bind(print, boost::asio::placeholders::error, &t ,&count);
t.async_wait(myfunc);
std::cout << "async wait " << std::endl;
io.run();
std::cout << "Just called io.run() " << std::endl;
std::cout << "Final count is " << count << std::endl;
return 0;
}
The async_wait() function seems to be blocking (i.e waiting for the 10 second timer to expire)
The output from the above program is as follows.
async wait
0
1
2
3
4
Just called io.run()
Final count is 5
I would expect an async_wait() to create a separate thread and wait for the timer to expire there meanwhile executing the main thread.
i.e I would expect the program to print
Just called io.run()
Final count is 5
while waiting for the timer to expire.? Is my understanding wrong?
This is my understanding of async_wait(). This implementation looks more like a blocking wait. Is my understanding wrong? What am I missing?
The io.run(); statement is the key to explaining the difference between the output you're getting and the output you're expecting.
In the ASIO framework, any asynchronous commands need to have a dedicated thread to run the callbacks upon. But because ASIO is relatively low-level, it expects you to provide the thread yourself.
As a result, what you're doing when you call io.run(); within the main thread is to specify to the framework that you intend to run all asynchronous commands on the main thread. That's acceptable, but that also means that the program will block on io.run();.
If you intend the commands to run on a separate thread, you'll have to write something like this:
std::thread run_thread([&]() {
io.run();
});
std::cout << "Just called io.run() " << std::endl;
std::cout << "Final count is " << count << std::endl;
run_thread.join();
return 0;
The async_wait function isn't blocking, run is. That's run's job. If you don't want a thread to block in the io_service's processing loop, don't have that thread call run.
The async_wait function doesn't create any threads. That would make it expensive and make it much harder to control the number of threads servicing the io_service.
Your expectation is unreasonable because returning from main terminates the process. So who or what would wait for the timer?
void sendCommand(float t,char* cmd)
{
std::clock_t endwait;
double endwait = clock () + t * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
if( clock() < endwait)
printf("\nThe waited command is =%s",cmd);
}
void Main()
{
sendCommand(3.0,"Command1");
sendCommand(2.0,"Command2");
printf("\nThe first value")
return 0;
}
i want to delay a function but my application should keep on running.
In the above code i want The first value to be printed first.
than i want Command2 to be printed and Command1 should be the last to be printed.
I prefer std::async for this.
#include <chrono>
#include <thread>
#include <future>
#include <iostream>
void sendCommand(std::chrono::seconds delay, std::string cmd)
{
std::this_thread::sleep_for( delay );
std::cout << "\nThe waited command is =" << cmd;
}
int main()
{
auto s1 = std::async(std::launch::async, sendCommand, std::chrono::seconds(3),"Command1");
auto s2 = std::async(std::launch::async, sendCommand, std::chrono::seconds(2),"Command2");
std::cout << "\nThe first value" << std::flush;
s1.wait();
s2.wait();
return 0;
}
However, for a real design, I would create a scheduler (or preferably use an existing one) which manages a priority queue sorted by the delay time. Spawning a new thread for every command will quickly become a problem. Since you flagged the question for MS VIsual C++, take a look the PPL which implements task-based parallelism.
And as it a C++ question, I would stay away from the C stuff and not use printf, CLOCK_PER_SEC, char*, clock etc. You will quickly get into problems even with this simple example when you start using strings instead of the "Command1" literals. std::string will help you here.
I think you need threads. You can do it like this:
#include <thread>
#include <chrono>
#include <iostream>
void sendCommand(float t, char const* cmd)
{
std::this_thread::sleep_for(std::chrono::milliseconds(int(t * 1000)));
std::cout << "\nThe waited command is = " << cmd << '\n';
}
int main()
{
// each function call on a new thread
std::thread t1(sendCommand, 3.0, "Command1");
std::thread t2(sendCommand, 2.0, "Command2");
// join the threads so we don't exit before they finish.
t1.join();
t2.join();
}
You can do it in many ways depending upon your actual logic.
Examles;:
1.you can you a global flag variable and check its state , when third print will complete you can set flag to 1,so next call will execute.
2.you can use a STACK .push all the function pointers in a STACK . and after that pop and execute.
3.MultiThreading. You can use it with proper synchronized way, but it will be complex. It depends upon your requirement.
Thanks !!!
boost::asio is nice because it doesn't require the overhead of multiple threads.
#include <iostream>
#include <boost/asio.hpp>
using namespace std;
int main()
{
boost::asio::io_service svc;
boost::asio::deadline_timer t0{svc};
boost::asio::deadline_timer t1{svc};
boost::asio::deadline_timer t2{svc};
t0.expires_from_now(boost::posix_time::seconds{1});
t1.expires_from_now(boost::posix_time::seconds{2});
t2.expires_from_now(boost::posix_time::seconds{3});
t2.async_wait([] (const boost::system::error_code& ec) { if(!ec) std::cout << "Greetings from t2!\n";});
t1.async_wait([] (const boost::system::error_code& ec) { if(!ec) std::cout << "Greetings from t1!\n";});
t0.async_wait([] (const boost::system::error_code& ec) { if(!ec) std::cout << "Greetings from t0!\n";});
svc.post([] () { std::cout << "I'm number one!\n";});
svc.run();
return 0;
}
Gives the output:
I'm number one!
Greetings from t0!
Greetings from t1!
Greetings from t2!