From 1ce27154d655dd768ddd855394f30969c476b9fb Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 9 Oct 2023 07:24:17 -0700 Subject: [PATCH] Replace comments: Document PRECONDITION. Adopt comment suggested by @tkoeppe: https://github.com/pybind/pybind11/pull/4877#discussion_r1350356093 --- include/pybind11/numpy.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 397e92769a..cb0e8a4e26 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -47,15 +47,18 @@ PYBIND11_NAMESPACE_BEGIN(detail) template class LazyInitializeAtLeastOnceDestroyNever { public: + // PRECONDITION: The GIL must be held when `Get()` is called. + // It is possible that multiple threads execute `Get()` with `initialized_` + // still being false, and thus proceed to execute `initialize()`. This can + // happen if `initialize()` releases and reacquires the GIL internally. + // We accept this, and expect the operation to be both idempotent and cheap. template T &Get(Initialize &&initialize) { if (!initialized_) { assert(PyGILState_Check()); - // Multiple threads may run this concurrently, but that is fine. - auto value = initialize(); // May release and re-acquire the GIL. - if (!initialized_) { // This runs with the GIL held, - new // therefore this is reached only once. - (reinterpret_cast(value_storage_)) T(std::move(value)); + auto value = initialize(); + if (!initialized_) { + new (reinterpret_cast(value_storage_)) T(std::move(value)); initialized_ = true; } }