I want a Timer class with reset method. When the reset method is called, std::function<void(void)> func execution will be postponed for next interval milliseconds. Here is my code (obtained from C++ 11: Calling a C++ function periodically) (the reset method doesn't work correctly):
// .h
class Timer
{
public:
Timer(const int interval, const std::function<void(void)>& func);
~Timer();
void stop();
void start();
bool is_running() const noexcept;
void reset();
private:
const int interval_;
const std::function<void(void)> func_;
std::atomic<bool> execute_;
std::thread thd_;
};
//////////////////////////////////////////////////////////////////////////////////
// .cpp
utl::Timer::Timer(const int interval, const std::function<void(void)>& func) :
func_{ func },
interval_{ interval },
execute_(false)
{
}
utl::Timer::~Timer()
{
if (execute_.load(std::memory_order_acquire)) {
stop();
};
}
void utl::Timer::stop()
{
execute_.store(false, std::memory_order_release);
if (thd_.joinable())
thd_.join();
}
void utl::Timer::start()
{
if (execute_.load(std::memory_order_acquire)) {
stop();
};
execute_.store(true, std::memory_order_release);
thd_ = std::thread([this]()
{
while (execute_.load(std::memory_order_acquire)) {
func_();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval_));
}
});
}
bool utl::Timer::is_running() const noexcept {
return (execute_.load(std::memory_order_acquire) &&
thd_.joinable());
}
void utl::Timer::reset()
{
stop();
start();
}
//////////////////////////////////////////////////////////////////////////////////
// a main function for test
#include <iostream>
using namespace std;
using namespace utl;
int main()
{
Timer timer(5000, []() {
cout << "reached!" << endl;
});
timer.start();
while (true)
{
cout << "working ...";
this_thread::sleep_for(std::chrono::seconds(1));
timer.reset();
}
}
This output of the main function (it is expected that string "reached!" not showed in cmd):
working ... reached! working ... reached! working
... reached! . . .
My problems are:
after calling start the func object is called without any delay.
reset method does not work
Related
I have asked a simpler version of this question before and got the correct answer: Thread pools not working with large number of tasks
Now I am trying to run tasks from an object of a class in parallel using a thread pool. My task is simple and only prints a number for that instance of class. I am expecting numbers 0->9 get printed but instead I get some numbers get printed more than once and some numbers not printed at all. Can anyone see what I am doing wrong with creating tasks in my loop?
#include "iostream"
#include "ThreadPool.h"
#include <chrono>
#include <thread>
using namespace std;
using namespace dynamicThreadPool;
class test {
int x;
public:
test(int x_in) : x(x_in) {}
void task()
{
cout << x << endl;
}
};
int main(void)
{
thread_pool pool;
for (int i = 0; i < 10; i++)
{
test* myTest = new test(i);
std::function<void()> myFunction = [&] {myTest->task(); };
pool.submit(myFunction);
}
while (!pool.isQueueEmpty())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
cout << "waiting for tasks to complete" << endl;
}
return 0;
}
And here is my thread pool, I got this definition from "C++ Concurrency in Action" book:
#pragma once
#include <queue>
#include <future>
#include <list>
#include <functional>
#include <memory>
template<typename T>
class threadsafe_queue
{
private:
mutable std::mutex mut;
std::queue<T> data_queue;
std::condition_variable data_cond;
public:
threadsafe_queue() {}
void push(T new_value)
{
std::lock_guard<std::mutex> lk(mut);
data_queue.push(std::move(new_value));
data_cond.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this] {return !data_queue.empty(); });
value = std::move(data_queue.front());
data_queue.pop();
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty())
return false;
value = std::move(data_queue.front());
data_queue.pop();
return true;
}
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
};
class join_threads
{
std::vector<std::thread>& threads;
public:
explicit join_threads(std::vector<std::thread>& threads_) : threads(threads_) {}
~join_threads()
{
for (unsigned long i = 0; i < threads.size(); i++)
{
if (threads[i].joinable())
{
threads[i].join();
}
}
}
};
class thread_pool
{
std::atomic_bool done;
threadsafe_queue<std::function<void()> > work_queue;
std::vector<std::thread> threads;
join_threads joiner;
void worker_thread()
{
while (!done)
{
std::function<void()> task;
if (work_queue.try_pop(task))
{
task();
}
else
{
std::this_thread::yield();
}
}
}
public:
thread_pool() : done(false), joiner(threads)
{
unsigned const thread_count = std::thread::hardware_concurrency();
try
{
for (unsigned i = 0; i < thread_count; i++)
{
threads.push_back(std::thread(&thread_pool::worker_thread, this));
}
}
catch (...)
{
done = true;
throw;
}
}
~thread_pool()
{
done = true;
}
template<typename FunctionType>
void submit(FunctionType f)
{
work_queue.push(std::function<void()>(f));
}
bool isQueueEmpty()
{
return work_queue.empty();
}
};
There's too much code to analyse all of it but you take a pointer by reference here:
{
test* myTest = new test(i);
std::function<void()> myFunction = [&] {myTest->task(); };
pool.submit(myFunction);
} // pointer goes out of scope
After that pointer has gone out of scope you will have undefined behavior if you later do myTest->task();.
To solve that immediate problem, copy the pointer and delete the object afterwards to not leak memory:
{
test* myTest = new test(i);
std::function<void()> myFunction = [=] {myTest->task(); delete myTest; };
pool.submit(myFunction);
}
I suspect this could be solved without using new at all, but I'll leave that up to you.
I am trying to make a thread safe queue in C++17 based on condition variables.
How do I correctly interrupt the WaitAndPop() method in the queue's destructor?
The problem is that user classes will be waiting on the WaitAndPop() call to return before they destruct, meaning that their member queue never destructs, meaning that the return never happens, and I have a deadlock.
Here is a simplified example that illustrates the problem:
#include <condition_variable>
#include <future>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
using namespace std;
using namespace chrono_literals;
class ThreadsafeQueue {
private:
condition_variable cv_;
bool cancel_;
mutex mut_;
queue<int> queue_;
public:
ThreadsafeQueue() : cancel_(false){};
~ThreadsafeQueue() {
// although this would stop the cv, it never runs.
cancel_ = true;
cv_.notify_all();
scoped_lock<mutex> lk(mut_);
}
void Push(int x) {
{
scoped_lock<mutex> lk(mut_);
queue_.push(x);
}
cv_.notify_all();
}
// returns true if successful
bool WaitAndPop(int &out) {
unique_lock<mutex> lk(mut_);
cv_.wait(lk, [this]() { return cancel_ || ! queue_.empty(); });
if (cancel_) return false;
out = queue_.front();
queue_.pop();
return true;
}
};
class MyClass {
private:
future<void> fill_fut_;
future<void> serve_fut_;
ThreadsafeQueue queue_;
bool running_;
public:
MyClass() : running_(true) {
fill_fut_ = async(launch::async, &MyClass::FillThread, this);
serve_fut_ = async(launch::async, &MyClass::ServeThread, this);
};
~MyClass() {
running_ = false;
fill_fut_.get();
serve_fut_.get(); // this prevents the threadsafe queue from destructing,
// which
// prevents the serve thread from stopping.
}
void FillThread() {
while (running_) {
queue_.Push(rand() & 100);
this_thread::sleep_for(200ms);
}
}
void ServeThread() {
while (running_) {
int x;
bool ok = queue_.WaitAndPop(x); // this never returns because the queue
// never destructs
if (ok)
cout << "popped: " << x << endl; // prints five times
else
cout << "pop failed"; // does not reach here
}
}
};
int main() {
MyClass obj;
this_thread::sleep_for(1s);
return 0;
}
The following code works:
class Handler {
public:
Application* application;
bool handle(sf::Event&);
};
class TestApp {
public:
TestApp();
bool running;
void run();
void attach_handler(Handler*);
std::forward_list<std::unique_ptr<Handler>> handlerFList;
};
TestApp::TestApp() {
}
void Application::run() {
while (running) {
sf::Event event;
while (window->pollEvent(event)) {
for (auto& handler : handlerFList) {
if (handler->handle(event)) {
break;
}
}
}
}
}
void Application::attach_handler(Handler* handler) {
handlerFList.push_front(std::unique_ptr<Handler>(std::move(handler)));
handler->application = this;
}
int main() {
sqt::TestApp app;
sqe::HandlerClose hc;
app.attach_handler(&hc);
app.run();
return 0;
}
But this one does not:
class Handler {
public:
Application* application;
bool handle(sf::Event&);
};
class TestApp {
public:
TestApp();
bool running;
void run();
void attach_handler(Handler*);
std::forward_list<std::unique_ptr<Handler>> handlerFList;
};
TestApp::TestApp() {
sqe::HandlerClose hc;
attach_handler(&hc);
}
void TestApp::run() {
while (running) {
sf::Event event;
while (window->pollEvent(event)) {
for (auto& handler : handlerFList) {
if (handler->handle(event)) { // SEGFAULTS
break;
}
}
}
}
}
void TestApp::attach_handler(Handler* handler) {
handlerFList.push_front(std::unique_ptr<Handler>(std::move(handler)));
handler->application = this;
}
int main() {
sqt::TestApp app;
app.run();
return 0;
}
It segfaults where marked. I can't work out what I'm doing wrong. Isn't std::move supposed to move the base object? What it seems like is happening is that once TestApp's constructor finishes, the object is getting deleted. How can I fix this?
Let's say I have this function:
void changeMap(Player* player, int map) {
player->setMap(map);
}
And I want a timer class that enables me to run that function after a certain amount of time, Something like this.
Player* chr;
int mapid = 300;
int milliseconds = 6000;
Timer.Schedule(changeMap(chr, 300), milliseconds);
Thanks in advance.
If this is a game loop then one way is to keep of list of events that you want to happen some time in the future where you store a time and a pointer to the function you want to call. (Or a std::function, or whatever). Keep the list sorted by time so the soonest event is a the top of the list.
Then in your main game loop, every loop, check the top of the list to see if the time of that event has been reached yet and if it has pop the event and call the function.
You can achieve the desired effect by the liberal use of Functor delegate objects and templates:
CAlarm.h
#ifndef CALARM_H
#define CALARM_H
#include "ADTtime.h"
#include "CStopwatch.h"
template<class FunctionObject>
class Alarm : public StopWatch {
public:
Alarm(const FunctionObject& fn);
Alarm(double tickTime, const FunctionObject& fn);
virtual ~Alarm();
FunctionObject Tick();
protected:
FunctionObject _delegate;
double _tickTime;
private:
};
template<class FunctionObject>
Alarm<FunctionObject>::Alarm(const FunctionObject& fn)
: StopWatch(), _delegate(fn), _tickTime(1.0) { }
template<class FunctionObject>
Alarm<FunctionObject>::Alarm(double tickTime, const FunctionObject& fn)
: StopWatch(), _delegate(fn), _tickTime(tickTime) { }
template<class FunctionObject>
Alarm<FunctionObject>::~Alarm() {
if(_isRunning) Stop();
}
template<class FunctionObject>
FunctionObject Alarm<FunctionObject>::Tick() {
if(IsRunning() == false) return _delegate;
if(GetElapsedTimeInSeconds() >= _tickTime) {
Reset();
_delegate();
}
return _delegate;
}
#endif
CStopwatch.h
#ifndef CSTOPWATCH_H
#define CSTOPWATCH_H
#include "ADTtime.h"
class StopWatch : public ADTTime {
public:
StopWatch();
virtual ~StopWatch();
void Start();
void Restart();
void Stop();
void Reset();
virtual void CalculateElapsedTime();
virtual double GetElapsedTimeInSeconds();
virtual double GetElapsedTimeInMilliseconds();
protected:
private:
};
#endif
CStopwatch.cpp
#include "CStopwatch.h"
StopWatch::StopWatch() : ADTTime() {
/* DO NOTHING. ALL INITIALIZATION HAPPENS IN BASE CLASS */
}
StopWatch::~StopWatch() {
_startTime = -1;
_endTime = -1;
_deltaTime = -1.0;
_isRunning = false;
}
void StopWatch::Start() {
if(_isRunning == true) return;
_startTime = clock();
_isRunning = true;
}
void StopWatch::Stop() {
if(_isRunning == false) return;
_isRunning = false;
CalculateElapsedTime();
}
void StopWatch::Restart() {
Reset();
Start();
}
void StopWatch::Reset() {
Stop();
_startTime = 0;
_endTime = 0;
_deltaTime = 0.0;
}
void StopWatch::CalculateElapsedTime() {
_endTime = clock();
_deltaTime = difftime(_startTime, _endTime);
}
double StopWatch::GetElapsedTimeInSeconds() {
CalculateElapsedTime();
return -ADTTime::GetElapsedTimeInSeconds();
}
double StopWatch::GetElapsedTimeInMilliseconds() {
CalculateElapsedTime();
return -ADTTime::GetElapsedTimeInMilliseconds();
}
ADTTime.h
#ifndef ADTTIME_H
#define ADTTIME_H
#include <ctime>
class ADTTime {
public:
clock_t GetStartTime() const;
clock_t GetStartTime();
double GetStartTimeInSeconds() const;
double GetStartTimeInSeconds();
clock_t GetEndTime() const;
clock_t GetEndTime();
double GetEndTimeInSeconds() const;
double GetEndTimeInSeconds();
virtual double GetElapsedTimeInSeconds();
virtual double GetElapsedTimeInMilliseconds();
virtual void CalculateElapsedTime()=0;
bool IsRunning() const;
bool IsRunning();
virtual void Start()=0;
virtual void Restart()=0;
virtual void Stop()=0;
virtual void Reset()=0;
ADTTime();
virtual ~ADTTime();
protected:
bool _isRunning;
clock_t _startTime;
clock_t _endTime;
double _deltaTime;
private:
};
#endif
CADTTime.cpp
#include "ADTtime.h"
clock_t ADTTime::GetStartTime() const {
return _startTime;
}
clock_t ADTTime::GetStartTime() {
return static_cast<const ADTTime&>(*this).GetStartTime();
}
double ADTTime::GetStartTimeInSeconds() const {
return static_cast<double>((_startTime / CLOCKS_PER_SEC));
}
double ADTTime::GetStartTimeInSeconds() {
return static_cast<const ADTTime&>(*this).GetStartTimeInSeconds();
}
clock_t ADTTime::GetEndTime() const {
return _endTime;
}
clock_t ADTTime::GetEndTime() {
return static_cast<const ADTTime&>(*this).GetEndTime();
}
double ADTTime::GetEndTimeInSeconds() const {
return static_cast<double>((_endTime / CLOCKS_PER_SEC));
}
double ADTTime::GetEndTimeInSeconds() {
return static_cast<const ADTTime&>(*this).GetEndTimeInSeconds();
}
double ADTTime::GetElapsedTimeInSeconds() {
return _deltaTime / CLOCKS_PER_SEC;
}
double ADTTime::GetElapsedTimeInMilliseconds() {
return _deltaTime;
}
bool ADTTime::IsRunning() const {
return _isRunning;
}
bool ADTTime::IsRunning() {
return static_cast<const ADTTime&>(*this).IsRunning();
}
ADTTime::ADTTime() : _isRunning(false), _startTime(-1), _endTime(-1), _deltaTime(-1.0) { }
ADTTime::~ADTTime() {
_isRunning = false;
_startTime = -1;
_endTime = -1;
_deltaTime = -1.0;
}
Since you are running on Windows OS, I don't understand why are you reinventing the wheel?
CComPtr<IReferenceClock> pReferenceClock;
HRESULT hr = CoCreateInstance( CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, IID_IReferenceClock, (void**)&pReferenceClock );
hr = pReferenceClock->AdviseTime( ... );
// or, hr = pReferenceClock->AdvisePeriodic( ... );
and once you are done,
hr = pReferenceClock->Unadvise( adviseCookie );
You can implement a simple (perhaps a bit rough around the edges) function that fire off a one-off event, like a timer, after a specified amount of milliseconds, using std::thread and std::chrono facilities
Something like that:
void doAfter( const std::function<void(void)>& f,
size_t intervalMs )
{
std::thread t{[f, intervalMs] () -> void
{
auto chronoInterval = std::chrono::milliseconds( intervalMs );
std::this_thread::sleep_for( chronoInterval );
f();
}
};
// You can either `t.detach()` the thread, or wait to `join` it in main
}
I am trying to build a very simple scheduler. It allows tasks (functions) to be added to a list and run on set intervals. The 'Scheduler' class works fine if I provide a static function as an argument to its 'ScheduleTask' member.
class TestController
{
private:
Scheduler _scheduler;
public:
TestController(void)
{
_scheduler.ScheduleTask(Task1, 3000);
_scheduler.ScheduleTask(Task2, 5000);
}
~TestController(void);
void Task1(void) { }
void Task2(void) { }
};
struct Task
{
long interval;
long last_run;
void (*TaskCallback) (void);
Task()
{
last_run = 0;
}
};
class Scheduler
{
private:
std::vector<Task> _tasks;
public:
Scheduler(void) { }
~Scheduler(void) { }
void ScheduleTask(void (*TaskCallback) (void), long interval)
{
Task t;
t.TaskCallback = TaskCallback;
t.interval = interval;
_tasks.push_back(t);
}
void loop()
{
for(unsigned int i = 0; i < _tasks.size(); i++)
{
long elapsed = clock();
if(elapsed - _tasks[i].last_run >= _tasks[i].interval)
{
_tasks[i].last_run = elapsed;
_tasks[i].TaskCallback();
}
}
}
};
How can I modify the callback to accept the member on the already instantiated 'TestController' object?
Use a combination of boost::function and boost::bind. Alternatively, use std::function and std::bind if your compiler supports them.
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <vector>
typedef boost::function<void()> Callback;
struct Task
{
long interval;
long last_run;
Callback TaskCallback;
Task()
{
last_run = 0;
}
};
class Scheduler
{
private:
std::vector<Task> _tasks;
public:
Scheduler(void) { }
~Scheduler(void) { }
void ScheduleTask(const Callback& TaskCallback, long interval)
{
Task t;
t.TaskCallback = TaskCallback;
t.interval = interval;
_tasks.push_back(t);
}
void loop()
{
for(unsigned int i = 0; i < _tasks.size(); i++)
{
long elapsed = clock();
if(elapsed - _tasks[i].last_run >= _tasks[i].interval)
{
_tasks[i].last_run = elapsed;
_tasks[i].TaskCallback();
}
}
}
};
class TestController
{
private:
Scheduler _scheduler;
public:
TestController(void)
{
_scheduler.ScheduleTask(boost::bind(&TestController::Task1,this), 3000);
_scheduler.ScheduleTask(boost::bind(&TestController::Task2,this), 5000);
}
~TestController(void);
void Task1(void) { }
void Task2(void) { }
};