I have the following class:
class Timer
{
public:
Timer(){};
~Timer(){};
void timer(int);
//...
private:
//...
};
My function timer(int value) is a callback that I use in glutTimerFunc(), inside the function timer(int value) i need to use the function timer again, something like this:
void Timer::timer(int value)
{
//...
glutTimerFunc(state->getTimer(), this->timer, 0);
}
How can i do it without using a static function?
you'll need a global dispatcher that turns the int passed to glutTimerFunc into a c++ callback (member function, lambda, etc)
something like this
struct timer_dispatch
{
using callback_t = std::function<void()>;
int start_timer(int msecs, callback_t callback) {
std::unique_lock<std::mutex> lock(_mutex);
int ident = _next_id++;
_callbacks.emplace(ident, std::move(callback));
glutTimerFunc(msecs, &timer_dispatch::dispatch_timer, ident);
return ident;
}
// implement similar function for stop timer - don't forget the mutex
void stop_timer(int ident) {
std::unique_lock<std::mutex> lock(_mutex);
_callbacks.erase(ident);
}
static timer_dispatch& instance() {
static timer_dispatch _;
return _;
}
private:
// private constructor ensures use via the instance() static method;
timer_dispatch() = default;
static void dispatch_timer(int ident) {
auto self = instance();
std::unique_lock<std::mutex> lock(self._mutex);
auto it = self._callbacks.find(ident);
if (it != self._callbacks.end()) {
auto my_copy = std::move(it->second);
self._callbacks.erase(it);
lock.unlock();
my_copy();
}
}
private:
std::unordered_map<int, callback_t> _callbacks;
std::mutex _mutex;
int _next_id = 0;
};
now use like so:
// start my timer:
void myclass::start_alien() {
...
_alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
...
}
void myclass::on_alien_timeout() {
// make alien do something, possibly restart a timer...
_alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
}
void myclass::on_alien_killed() {
timer_dispatch::instance().stop_timer(_alien_timer_id);
_alien_timer_id = -1;
}
Related
Let me start with a short example
class A
{
public:
A() :
thread_([this] {
std::unique_lock<std::mutex> lk(mtx_);
cv_.wait(lk, [this] { return quit_; });
})
{
throw std::exception();
}
~A()
{
quit_ = true;
cv_.notify_one();
thread_.join();
}
private:
bool quit_ = false;
std::mutex mtx_;
std::condition_variable cv_;
std::thread thread_;
};
int main()
{
try { A a; }
catch (...) {}
// Does not reach this point
}
Because an exception is thrown in the constructor, the members are being destructed in reverse order.
the thread_ member is still joinable so terminate is being called.
It is pretty straightforward to write a thread wrapper class with a customizable destructor.
For example, something like that:
class ThreadWrapper
{
public:
ThreadWrapper(std::function<void(std::thread & t)> onDestruct, std::thread&& thread) :
onDestruct_(onDestruct),
thread_(std::move(thread))
{
}
~ThreadWrapper()
{
onDestruct_(thread_);
}
private:
std::function<void(std::thread & t)> onDestruct_;
std::thread thread_;
};
class B
{
public:
B() :
thread_(
[this](std::thread& t) {
quit_ = true;
cv_.notify_one();
t.join();
},
std::thread([this] {
std::unique_lock<std::mutex> lk(mtx_);
cv_.wait(lk, [this] { return quit_; });
}))
{
throw std::exception();
}
private:
bool quit_ = false;
std::mutex mtx_;
std::condition_variable cv_;
ThreadWrapper thread_;
};
However, I was surprised not to find something like that in the boost library.
The closest thing I found is the scoped_thread which lets you pass a specific action as a template parameter.
Am I missing something?
I am coding a wrapper MyTest that is containing a std::function<> used for storing callback.
The wrappers are contained in a std::vector tests of shared_ptr<>.
emplace_back a single wrapper in the vector works, i.e. the std::function callback can be fired. If I have two objects in the vector, only the last object callback works.
Here are my classes:
typedef function<void(const uint64_t &)> CallBackFunc_t;
class MyWheel
{
private:
class test
{
private:
const CallBackFunc_t &callback;
public:
test(const CallBackFunc_t &cb);
bool work();
};
public:
vector<shared_ptr<test>> tests;
int addTest(const CallBackFunc_t &test_callback);
void spin(void);
};
class MyTest
{
private:
int handle = -1;
MyWheel &wheel;
public:
MyTest(MyWheel &whl);
int setCallback(const CallBackFunc_t &callback);
};
And the source.
MyWheel::test::test(const CallBackFunc_t &cb) : callback(cb)
{
}
bool MyWheel::test::work()
{
callback(0);
return true;
}
int MyWheel::addTest(const CallBackFunc_t &test_callback)
{
tests.emplace_back(new test(test_callback));
return (int)(test.size()-1);
}
void MyWheel::spin(void)
{
for(vector<shared_ptr<test>>::iterator test = tests.begin(); test != tests.end(); ++test)
{
(*test)->work();
}
}
MyTest::MyTest(MyWheel &whl) : wheel(whl)
{
};
int MyTest::setCallback(const CallBackFunc_t &callback)
{
if(handle < 0)
{
handle = wheel.addTest(callback);
}
return handle;
}
Usage:
MyWheel wh;
MyTest t1(wh);
MyTest t2(wh);
t1.setCallback([&](const uint64_t &e) {
cout <<"1\r\n";
});
t2.setCallback([&](const uint64_t &e) {
cout <<"2\r\n";
});
while(true)
{
wh.spin();
}
I expect "1" and "2" to be printed when running, but only "2" is...
What am I doing wrong?
You need to store callback by copy:
class test
{
private:
CallBackFunc_t callback; // <---- make a copy of callback
public:
test(const CallBackFunc_t &cb);
bool work();
};
now you have undefined behaviour, because you are storing reference to callback which is destroyed at the end of this expression:
t1.setCallback([&](const uint64_t &e) {
cout <<"1\r\n";
}); // it causes dangling reference
If you want to stay with reference to callback inside test you need to create them as Lvalues before calling setCallback:
std::function<void (const uint64_t& )> callback1 = [](const uint64_t &e) {
cout <<"1\r\n";
};
t1.setCallback(callback1);
std::function<void (const uint64_t& )> callback2 = [](const uint64_t &e) {
cout <<"2\r\n";
};
t2.setCallback(callback2);
Hi rafix07 and thanks for the examples!
Yes, that did the trick, and adding & in the capture list made it possible to access variables where callback function was defined.
I.e.
bool var1 = false;
std::function<void (const uint64_t& )> callback1 = [&](const uint64_t &e) {
cout <<"1\r\n";
var1 = true;
};
t1.setCallback(callback1);
I have class MyClass that can be modified by calling setX.
I want to know if an object of MyClass has been changed by calling isChanged.
In the code below, I don’t like to add setDirty or m_dataChanged in every method that can change the state of an object.
class ChangesHolder
{
private:
bool m_isChanged;
// boost::signals2::signal<void()> m_dataChanged;
// long m_stamps;
public:
ChangesHolder()
: m_isChanged{false}
// , m_stamps{0}
{
// m_dataChanged.connect(std::bind(&ChangesHolder::setDirty, this));
}
bool isChanged() const
{
return m_isChanged;
// return (m_stamps == 0);
}
void resetChanges()
{
m_isChanged = false;
// m_stamps = 0;
}
protected:
void setDirty()
{
m_isChanged = true;
// ++m_stamps;
}
}
class MyClass : public ChangesHolder
{
private:
int m_x;
public:
void setX(int x)
{
if (m_x != x)
{
m_x = x;
setDirty();
// m_dataChanged();
}
}
}
I want to register such methods like this:
template<typename ... Funcs>
void startTrack(Funcs ... funcs)
{
auto connect = [&](auto func)
{
// connect func to setDirty
};
do_foreach(connect, funcs ...);
}
MyClass::MyClass()
{
startTrack(&MyClass::setX, &MyClass::setY);
}
How can this be done or maybe there are other ways to do it?
I have a simple event class, everything works fine with it.
Im trying to add a template class that i can pass arguments to and then read it when wait finishes.
At the moment i have it working with struct only as i need to set the arg to 0 if im not using it.
Is there a better/easier way to do this so i can pass any type of argument to it?
class Event
{
public:
Event() : _signalled(false) {}
virtual void notify()
{
std::unique_lock<std::mutex> lock(_mutex);
_signalled = true;
_condvar.notify_one();
}
virtual void wait()
{
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock, [&] { return _signalled; });
_signalled = false;
}
void stop()
{
std::unique_lock<std::mutex> lock(_mutex);
_signalled = false;
}
private:
std::mutex _mutex;
std::condition_variable _condvar;
bool _signalled;
};
template <class T>
class ArgEvent : public Event
{
public:
void notify()
{
Event::notify();
this->arg = { 0 };
}
void notify(T arg)
{
Event::notify();
this->arg = arg;
}
T getArg()
{
return this->arg;
}
void wait()
{
Event::wait();
}
void wait(T& arg)
{
Event::wait();
arg = this->arg;
}
private:
T arg;
};
Boost.Optional allows the implementation to work without c++17.
https://www.boost.org/doc/libs/1_67_0/libs/optional/doc/html/index.html
I have a function that takes a long time to run, but thankfully it runs asynchronously. I want to take the result of this function call and set it to a class instance's private variable. Seems easy:
// Exists in some other library.
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A {
public:
void Do() {
auto lambda = [this](int val) {
// Some processing...
var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
A* a = new A;
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
The problem is adding the following line to main, right before the comment:
delete a;
Now when LongRunningAsync invokes the callback, it will attempt to modify a member variable of a deleted instance (which is UB).
Is there a way to salvage this approach? I've recently learned about the following solution:
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A : public std::enable_shared_from_this<A> {
public:
void Do() {
std::weak_ptr<A> weak = shared_from_this();
auto lambda = [weak](int val) {
auto shared = weak.lock();
if (!shared) return;
// Some processing...
shared->var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
auto a = std::make_shared<A>();
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
But it requires changing all A variables to shared_ptr. Is there a less intrusive way to make this work?
One possible solution is to just encapsulate the state you need into a shared_ptr member variable and then capture that by value into the closure that runs asynchronously.
Something like the following
class A : public std::enable_shared_from_this<A> {
public:
void Do() {
auto lambda = [member_shared_state](int val) {
member_shared_state->var_ = val;
};
LongRunningAsync(lambda);
}
....
};
Here's a solution based on Curious's approach, but that doesn't force me to change all pointers to A objects to shared_ptr:
// Exists in some other library.
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A {
public:
A() : var_(std::make_shared<int>()) {}
void Do() {
std::weak_ptr<int> weak = var_;
auto lambda = [weak](int val) {
auto shared = weak.lock();
if (!shared) {
return;
}
// Some processing...
*shared = val;
};
LongRunningAsync(lambda);
}
private:
std::shared_ptr<int> var_;
};
int main() {
A* a = new A;
a->Do();
delete a;
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}