Reputation: 3125
I have a bool value that is constantly streaming. I need to trigger a function when the bool becomes true, and another when the bool becomes false, but only once per change, so I cannot use a while(true)
loop.
What is the best way in c++ to 'watch' a value and trigger when it changes?
Thank you.
Upvotes: 2
Views: 8201
Reputation: 5242
A little late to the party, but here's a slightly simpler solution if you just want to bang it out (like for testing):
/**
* @brief Set a boolean variable.
* @param b Pointer to the boolean variable.
* @param value Set to this value.
* @return Returns if the value was to be changed.
*/
bool set(bool* b, bool value)
{
// if b isn't going to change
if (*b == value) return false;
// if b is going to change
else
{
*b = value;
return true;
}
}
/**
* @brief A possible implementation
*/
int main()
{
bool my_variable = false;
while(true)
{
// Set my_variable and flag it if it changed
bool changed = set(&my_variable, some_function());
// check for changed
if (changed)
{
// ...
}
}
}
This seems a bit less overkill than implementing boolean wrapper classes, triggers, and observer-patterns.
Upvotes: 0
Reputation: 69902
I'd probably start with something like this:
#include <functional>
#include <atomic>
#include <iostream>
struct trigger
{
using closure_type = std::function<void()>;
trigger(closure_type on_set, closure_type on_reset, bool initial_state = false)
: _state { initial_state }
, _on_set(std::move(on_set))
, _on_reset(std::move(on_reset))
{}
void set() {
if (not _state.exchange(true)) {
_on_set();
}
}
void reset() {
if (_state.exchange(false)) {
_on_reset();
}
}
std::atomic<bool> _state;
std::function<void()> _on_set;
std::function<void()> _on_reset;
};
void has_set() {
// you can marshall accross threads here by posting calls to a
// queue
std::cout << __func__ << std::endl;
}
void has_unset() {
// you can marshall accross threads here by posting calls to a
// queue
std::cout << __func__ << std::endl;
}
int main()
{
trigger t { has_set, has_unset };
t.set();
t.set();
t.reset();
t.reset();
}
Upvotes: 1
Reputation: 635
Take a look at the Observer Pattern. You could wrap your boolean in a helper class, that triggers an event whenever the boolean is set.
Example implementation of an observable bool:
#include <vector>
class Observer {
public:
virtual void valueChanged() = 0;
};
class ObservableBool {
private:
bool value;
std::vector<Observer*> observers = std::vector<Observer*>();
public:
bool getValue() {
return value;
}
bool setValue(bool value) {
bool changed = (value != this->value);
this->value = value;
if(changed) raiseEvent();
}
void addObserver(Observer* observer) {
observers.push_back(observer);
}
void removeObserver(Observer* observer) {
observers.erase(std::find(observers.begin, observers.end, observer));
}
private:
void raiseEvent() {
for (int i = 0; i < observers.size; ++i) {
observers[i]->valueChanged();
}
}
};
This can be improved a lot. A really nice way would be to implement implicit conversion from and to bool (But be careful, overloadig the '=' operator for bool could be dangerous). You could template it to support arbitrary types instead of just bool, you should use smart pointer instead of raw pointers (std::weak_ptr
would be best) and instead of a Observer class you should probably use function pointers to properly support lambdas. If you do it right you can use the class just like a normal boolean, with a small overhead when a new value is set. And by default, all reactions to a change are executed by the thread that changed the value.
Upvotes: 0
Reputation: 1934
I would go about this by setting a flagTrue variable and a flagFalse variable. When you encounter the first True, flagTrue changes from false to true and all following True booleans are ignored. Similarly, when you encounter your firat False, flagFalse would change from False to True and ignore all following False booleans. Also, when the boolean being checked changes from True to False, you will change flagTrue to False and similarly in the other case.
Example:
flagTrue = false
flagFalse = false
if (bool == true && flagTrue == false)
{
// DoSomething
flagTrue = true;
flagFalse = false;
}
else if (bool == false && flagFalse == false)
{
// DoSomething
flagTrue = false;
flagFalse = true;
}
Upvotes: 1