critical_section.h 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. // Copyright (c) 2016-2025 The Pybind Development Team.
  2. // All rights reserved. Use of this source code is governed by a
  3. // BSD-style license that can be found in the LICENSE file.
  4. #pragma once
  5. #include "pytypes.h"
  6. PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
  7. /// This does not do anything if there's a GIL. On free-threaded Python,
  8. /// it locks an object. This uses the CPython API, which has limits
  9. class scoped_critical_section {
  10. public:
  11. #ifdef Py_GIL_DISABLED
  12. explicit scoped_critical_section(handle obj1, handle obj2 = handle{}) {
  13. if (obj1) {
  14. if (obj2) {
  15. PyCriticalSection2_Begin(&section2, obj1.ptr(), obj2.ptr());
  16. rank = 2;
  17. } else {
  18. PyCriticalSection_Begin(&section, obj1.ptr());
  19. rank = 1;
  20. }
  21. } else if (obj2) {
  22. PyCriticalSection_Begin(&section, obj2.ptr());
  23. rank = 1;
  24. }
  25. }
  26. ~scoped_critical_section() {
  27. if (rank == 1) {
  28. PyCriticalSection_End(&section);
  29. } else if (rank == 2) {
  30. PyCriticalSection2_End(&section2);
  31. }
  32. }
  33. #else
  34. explicit scoped_critical_section(handle, handle = handle{}) {};
  35. ~scoped_critical_section() = default;
  36. #endif
  37. scoped_critical_section(const scoped_critical_section &) = delete;
  38. scoped_critical_section &operator=(const scoped_critical_section &) = delete;
  39. private:
  40. #ifdef Py_GIL_DISABLED
  41. int rank{0};
  42. union {
  43. PyCriticalSection section;
  44. PyCriticalSection2 section2;
  45. };
  46. #endif
  47. };
  48. PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)