How can I safely share a variable between embedded Python script and C++ code in a multi-threaded application?
I’m working on integrating Python into a C++ application to read data from an I2C sensor using a Python script. The goal is to have both the Python and C++ parts of the code running in parallel, allowing for continuous updates and access to the Python variable from C++.
To achieve this, I’ve created a thread in C++ that runs the Python script, which fetches the sensor data and updates a variable every second using an infinite loop. However, I’m facing an issue where I need to pass this updated variable from the Python script to the C++ code for further use elsewhere in the application.
I’ve attempted to do this by defining a global atomic variable in C++ and updating it from the Python script. However, I’m not sure if this is the most efficient or correct approach.
I’m using a Raspberry Pi 5 with Python 3.10
The question:
-
How can I safely share a variable between the embedded Python script and the C++ code in a multi-threaded environment?
-
Is there a better way to structure my code to enable continuous updates and access to the Python variable from C++?
-
Are there any potential synchronization issues I should be aware of when accessing the shared variable?
Here’s the relevant part of my code:
#include <Python.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
// Global variable to store the velocity as an atomic float to ensure thread-safe updates.
std::atomic<float> globalVelocity(0.0);
void UpdateVelocity() {
Py_Initialize();
PyObject* sysPath = PySys_GetObject("path");
PyList_Append(sysPath, PyUnicode_FromString("/path/to/your/module"));
PyObject *pName = PyUnicode_DecodeFSDefault("velocity_module");
PyObject *pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
PyObject *pFunc = PyObject_GetAttrString(pModule, "get_velocity");
if (pFunc && PyCallable_Check(pFunc)) {
while (true) {
PyObject *pValue = PyObject_CallObject(pFunc, NULL);
if (pValue != NULL) {
double velocity = PyFloat_AsDouble(pValue);
globalVelocity.store(static_cast<float>(velocity));
std::cout << "Updated Velocity: " << velocity << " m/s" << std::endl;
Py_DECREF(pValue);
} else {
PyErr_Print();
std::cerr << "Function call failed" << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
} else {
PyErr_Print();
std::cerr << "Cannot find function 'get_velocity'" << std::endl;
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
} else {
PyErr_Print();
std::cerr << "Failed to load 'velocity_module'" << std::endl;
}
Py_Finalize();
}
int main() {
std::thread velocityThread(UpdateVelocity);
velocityThread.detach();
while (true) {
std::cout << "Main thread reading global velocity: " << globalVelocity.load() << " m/s" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
Thanks in advance to anyone who takes the time to read this!