Refactored how/when python interpretor is created to simplify library usage

This commit is contained in:
matlabbe
2026-05-26 11:01:04 -07:00
parent 49aa566613
commit 7681e83c32
12 changed files with 48 additions and 52 deletions
+12 -4
View File
@@ -21,16 +21,24 @@ class gil_scoped_release;
namespace rtabmap { namespace rtabmap {
/** /**
* Create a single PythonInterface on main thread at * Process-wide singleton owning the embedded Python interpreter.
* global scope before any Python classes. * Call PythonInterface::instance() from the main thread (typically near
* the top of main()) before any Python-using class is constructed.
*/ */
class RTABMAP_CORE_EXPORT PythonInterface class RTABMAP_CORE_EXPORT PythonInterface
{ {
public: public:
PythonInterface(); // Pass a caller tag (e.g. class name) so the main-thread assertion
virtual ~PythonInterface(); // can report who triggered the first construction.
static PythonInterface & instance(const std::string & caller = "");
PythonInterface(const PythonInterface &) = delete;
PythonInterface & operator=(const PythonInterface &) = delete;
private: private:
explicit PythonInterface(const std::string & caller);
~PythonInterface();
pybind11::scoped_interpreter* guard_; pybind11::scoped_interpreter* guard_;
pybind11::gil_scoped_release* release_; pybind11::gil_scoped_release* release_;
}; };
-6
View File
@@ -50,7 +50,6 @@ class Memory;
class BayesFilter; class BayesFilter;
class Signature; class Signature;
class Optimizer; class Optimizer;
class PythonInterface;
class RTABMAP_CORE_EXPORT Rtabmap class RTABMAP_CORE_EXPORT Rtabmap
{ {
@@ -401,11 +400,6 @@ private:
Transform _pathTransformToGoal; Transform _pathTransformToGoal;
int _pathStuckCount; int _pathStuckCount;
float _pathStuckDistance; float _pathStuckDistance;
#ifdef RTABMAP_PYTHON
PythonInterface * _python;
#endif
}; };
} // namespace rtabmap } // namespace rtabmap
+6 -3
View File
@@ -181,10 +181,13 @@ Rtabmap::Rtabmap() :
_pathTransformToGoal(Transform::getIdentity()), _pathTransformToGoal(Transform::getIdentity()),
_pathStuckCount(0), _pathStuckCount(0),
_pathStuckDistance(0.0f) _pathStuckDistance(0.0f)
#ifdef RTABMAP_PYTHON
,_python(new PythonInterface())
#endif
{ {
#ifdef RTABMAP_PYTHON
// Ensure the embedded Python interpreter is up. The first call here will
// assert that it runs on the main thread; callers building Rtabmap on a
// worker thread should construct the singleton in main() beforehand.
PythonInterface::instance("Rtabmap");
#endif
} }
Rtabmap::~Rtabmap() { Rtabmap::~Rtabmap() {
+1
View File
@@ -23,6 +23,7 @@ PyDescriptor::PyDescriptor(
dim_(Parameters::defaultPyDescriptorDim()) dim_(Parameters::defaultPyDescriptorDim())
{ {
UDEBUG(""); UDEBUG("");
PythonInterface::instance("PyDescriptor");
this->parseParameters(parameters); this->parseParameters(parameters);
} }
+1
View File
@@ -24,6 +24,7 @@ PyDetector::PyDetector(const ParametersMap & parameters) :
path_(Parameters::defaultPyDetectorPath()), path_(Parameters::defaultPyDetectorPath()),
cuda_(Parameters::defaultPyDetectorCuda()) cuda_(Parameters::defaultPyDetectorCuda())
{ {
PythonInterface::instance("PyDetector");
this->parseParameters(parameters); this->parseParameters(parameters);
UDEBUG("path = %s", path_.c_str()); UDEBUG("path = %s", path_.c_str());
+1
View File
@@ -30,6 +30,7 @@ PyMatcher::PyMatcher(
iterations_(iterations), iterations_(iterations),
cuda_(cuda) cuda_(cuda)
{ {
PythonInterface::instance("PyMatcher");
path_ = uReplaceChar(pythonMatcherPath, '~', UDirectory::homeDir()); path_ = uReplaceChar(pythonMatcherPath, '~', UDirectory::homeDir());
model_ = uReplaceChar(model, '~', UDirectory::homeDir()); model_ = uReplaceChar(model, '~', UDirectory::homeDir());
UINFO("path = %s", path_.c_str()); UINFO("path = %s", path_.c_str());
+27 -2
View File
@@ -8,14 +8,39 @@
#include <rtabmap/core/PythonInterface.h> #include <rtabmap/core/PythonInterface.h>
#include <rtabmap/utilite/ULogger.h> #include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UThread.h> #include <rtabmap/utilite/UThread.h>
#include <rtabmap/utilite/UConversion.h>
#include <pybind11/embed.h> #include <pybind11/embed.h>
#include <filesystem> #include <filesystem>
#include <thread>
namespace rtabmap { namespace rtabmap {
PythonInterface::PythonInterface() namespace {
// Captured when librtabmap_core is loaded. The dynamic loader runs static
// initializers on the main thread before main(), so this records the main
// thread id (as long as the library isn't dlopen'd from a worker thread).
const std::thread::id g_mainThreadId = std::this_thread::get_id();
}
PythonInterface & PythonInterface::instance(const std::string & caller)
{ {
UINFO("Initialize python interpreter"); // Meyers singleton: thread-safe construction in C++11, destroyed at exit.
// The constructor asserts it runs on the main thread; the caller tag
// from the first invocation is captured into the assertion message.
static PythonInterface inst(caller);
return inst;
}
PythonInterface::PythonInterface(const std::string & caller)
{
UASSERT_MSG(std::this_thread::get_id() == g_mainThreadId,
uFormat("PythonInterface must be created on the main thread "
"(first construction triggered by \"%s\"). Call "
"PythonInterface::instance() early in main() before "
"any worker thread touches a Python-backed class.",
caller.empty()?"<unspecified>":caller.c_str()).c_str());
UINFO("Initialize python interpreter (triggered by \"%s\")",
caller.empty()?"<unspecified>":caller.c_str());
guard_ = new pybind11::scoped_interpreter(); guard_ = new pybind11::scoped_interpreter();
// Tell Python to look in this directory for DLLs // Tell Python to look in this directory for DLLs
-8
View File
@@ -40,10 +40,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <pcl/filters/filter.h> #include <pcl/filters/filter.h>
#include <rtabmap/core/SensorCaptureThread.h> #include <rtabmap/core/SensorCaptureThread.h>
#ifdef RTABMAP_PYTHON
#include "rtabmap/core/PythonInterface.h"
#endif
#include "MapBuilder.h" #include "MapBuilder.h"
void showUsage() void showUsage()
@@ -77,10 +73,6 @@ int main(int argc, char * argv[])
ULogger::setType(ULogger::kTypeConsole); ULogger::setType(ULogger::kTypeConsole);
ULogger::setLevel(ULogger::kInfo); ULogger::setLevel(ULogger::kInfo);
#ifdef RTABMAP_PYTHON
PythonInterface python; // Make sure we initialize python in main thread
#endif
int driver = 0; int driver = 0;
if(argc < 2) if(argc < 2)
{ {
-8
View File
@@ -36,10 +36,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QApplication> #include <QApplication>
#include <stdio.h> #include <stdio.h>
#ifdef RTABMAP_PYTHON
#include "rtabmap/core/PythonInterface.h"
#endif
#include "MapBuilderWifi.h" #include "MapBuilderWifi.h"
#include "WifiThread.h" #include "WifiThread.h"
@@ -61,10 +57,6 @@ int main(int argc, char * argv[])
ULogger::setType(ULogger::kTypeConsole); ULogger::setType(ULogger::kTypeConsole);
ULogger::setLevel(ULogger::kWarning); ULogger::setLevel(ULogger::kWarning);
#ifdef RTABMAP_PYTHON
PythonInterface python; // Make sure we initialize python in main thread
#endif
std::string interfaceName = "wlan0"; std::string interfaceName = "wlan0";
int driver = 0; int driver = 0;
bool mirroring = false; bool mirroring = false;
-7
View File
@@ -28,9 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QApplication> #include <QApplication>
#include "rtabmap/gui/DatabaseViewer.h" #include "rtabmap/gui/DatabaseViewer.h"
#include "rtabmap/utilite/ULogger.h" #include "rtabmap/utilite/ULogger.h"
#ifdef RTABMAP_PYTHON
#include <rtabmap/core/PythonInterface.h>
#endif
#include <vtkObject.h> #include <vtkObject.h>
#include <vtkVersionMacros.h> #include <vtkVersionMacros.h>
@@ -53,10 +50,6 @@ int main(int argc, char * argv[])
QSurfaceFormat::setDefaultFormat(QVTKRenderWidget::defaultFormat()); QSurfaceFormat::setDefaultFormat(QVTKRenderWidget::defaultFormat());
#endif #endif
#ifdef RTABMAP_PYTHON
rtabmap::PythonInterface pythonInterface;
#endif
QApplication * app = new QApplication(argc, argv); QApplication * app = new QApplication(argc, argv);
rtabmap::DatabaseViewer * mainWindow = new rtabmap::DatabaseViewer(); rtabmap::DatabaseViewer * mainWindow = new rtabmap::DatabaseViewer();
-7
View File
@@ -42,9 +42,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UFile.h> #include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UStl.h> #include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UTimer.h> #include <rtabmap/utilite/UTimer.h>
#ifdef RTABMAP_PYTHON
#include <rtabmap/core/PythonInterface.h>
#endif
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <QApplication> #include <QApplication>
@@ -186,10 +183,6 @@ int main(int argc, char * argv[])
printf(" --raw (images will be rectified)\n"); printf(" --raw (images will be rectified)\n");
} }
#ifdef RTABMAP_PYTHON
rtabmap::PythonInterface pythonInterface;
#endif
ParametersMap parameters = Parameters::parseArguments(argc, argv); ParametersMap parameters = Parameters::parseArguments(argc, argv);
parameters.insert(ParametersPair(Parameters::kRegRepeatOnce(), "false")); parameters.insert(ParametersPair(Parameters::kRegRepeatOnce(), "false"));
-7
View File
@@ -37,9 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UTimer.h> #include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UFile.h> #include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UStl.h> #include <rtabmap/utilite/UStl.h>
#ifdef RTABMAP_PYTHON
#include <rtabmap/core/PythonInterface.h>
#endif
#include <pcl/filters/filter.h> #include <pcl/filters/filter.h>
#include <pcl/io/ply_io.h> #include <pcl/io/ply_io.h>
#include <pcl/io/obj_io.h> #include <pcl/io/obj_io.h>
@@ -119,10 +116,6 @@ int main(int argc, char * argv[])
printf(" keep_linked = %s\n", keepLinked?"true":"false"); printf(" keep_linked = %s\n", keepLinked?"true":"false");
printf(" pre_cleanup = %s\n", preCleanup?"true":"false"); printf(" pre_cleanup = %s\n", preCleanup?"true":"false");
#ifdef RTABMAP_PYTHON
rtabmap::PythonInterface pythonInterface;
#endif
// Just parse logging options // Just parse logging options
Parameters::parseArguments(argc, argv); Parameters::parseArguments(argc, argv);