I have some C code that contains roughly this logic:
class wrapper_info {
public:
bool isConnected();
void connectedHandler();
void disconnectedHandler();
protected:
bool _connected;
}
void wrapper_info::connectedHandler() {
_connected = true;
}
void wrapper_info::disconnectedHandler() {
_connected = false;
}
bool wrapper_info::isConnected() {
return _connected;
}
extern "C"
bool is_connected(void *obj) {
wrapper_info *wrapper_obj = reinterpret_cast<wrapper_info*>(obj);
return wrapper_obj->isConnected();
}
For reasons mostly out of my control, different threads (running on different CPU cores) call these functions in the following way.
Thread 1, 2, 3: is_connected(obj)
Thread 2: connectedHandler()
when the connection is initiated.
Thread 3 disconnectedHandler()
when the connection is broken.
I am thinking there could be issues in the event of repeated calls to connectedHandler()
and disconnectedHandler()
, issues with the two threads writing to _connected
and the writes getting out of order, resulting in the wrong final value. And potentially also issues with polling _connected
as well.
My questions are:
- What potential issues could actually arise from separate threads polling and modifying the value of
_connected
? - What options are there to prevent these? Perhaps making
_connected
avolatile bool
might solve issues polling the value. I was also thinking for the issue of threads 2 and 3 modifying its value, perhaps making it an atomic bool and using atomic set operations will be sufficient to prevent issues like out-of-order memory operations. I also know other potential solutions are locks or memory barriers like smb_mb. However, I am not sure what I should use.
Thank you lots.
CodePudding user response:
What potential issues could actually arise from separate threads polling and modifying the value of _connected?
It's Undefined Behavior, no matter what.
What options are there to prevent these?
A common solution is to use std::atomic<bool>
instead of bool
.
There are fancier (and much more complex) ways to ensure synchronization between threads, but std::atomic
is an excellent first choice, and not difficult to use correctly.
Perhaps making
_connected
avolatile bool
might solve issues
It won't. volatile
does not solve thread synchronization issues.