Lets suppose it is embedded development of some ARM controller. Lets suppose we have some variable, which can be assigned from an interrupt or "mainThread" - (is it a "main loop" or RTOS thread). In C world volatile
keyword should be used in this case and code may look like this:
/* Some subsystem .C file */
static volatile uint8_t state;
void on_main_thread(void) {
state = 1; /* Changing state in this context */
}
void on_interrupt(void) {
state = 0; /* Changing state from interrupt */
}
uint8_t get_state(void) {
return state; /* Getting the state in whatever context */
}
volatile
keyword is essential in this situation. Now our company rewrites some code to C++ and the same subsystem example looks like this (I use enum here to emphasize the problem)
class SomeSubsystem
{
public:
enum class States
{
Off,
Idle,
Up,
Down,
};
States getState() const { return mState; }
void onMainThread(void) {
mState = States::Idle; // Changing state in this context
}
// Somehow this function is called from the interrupt
void onInterrupt(void) {
mState = States::Up; // Changing state from interrupt
}
private:
States mState; // <-- Here! Volatile?
//...
};
Now States mState
should be volatile because it is shared among different contexts. But If one sets it as volatile... Then volatile
works like plague for C++ class and one have to volatilize everything around. Like volatile enum class States
, getState() volatile
etc. Which doesn't look good for me (am I wrong?)
So. What is the right way to handle this situation in C++?
P.S. I would try to define "this situation" as: "possible usage of a class members from different contexts like interrupts and normal code execution"
This could work if you only need a single instance of SomeSubsystem in your program (which I assume as per the c code you posted.
If you need multiple instances, then maybe you could modify mState to be a States array or some similar structure instead.
class SomeSubsystem
{
public:
enum class States
{
Off,
Idle,
Up,
Down,
};
States getState() const { return mState; }
void onMainThread(void) {
mState = States::Idle; // Changing state in this context
}
// Somehow this function is called from the interrupt
void onInterrupt(void) {
mState = States::Up; // Changing state from interrupt
}
// Make mState public in order to access it from the rest of your code
// Otherwise, keep it private and create static set/get functions
public:
static volatile States mState; // <-- Here! Volatile?
//...
};
Then define mState somewhere (eg. in SomeSubsystem.cpp)
volatile SomeSubsystem::States SomeSubsystem::mState = SomeSubsystem::States::Off;
Now you are able to access mState from anywhere in your code like this
SomeSubsystem::mState = SomeSubsystem::States::Off;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With