@@ -84,6 +84,9 @@ class RHistEngine final {
8484 // / The bin contents for this histogram
8585 std::vector<BinContentType> fBinContents ;
8686
87+ // / Flag to pause filling while a snapshot is ongoing
88+ mutable std::atomic<bool > fSnapshot {false }; // !
89+
8790public:
8891 // / Construct a histogram engine.
8992 // /
@@ -134,7 +137,7 @@ public:
134137 // / Efficiently move construct a histogram engine.
135138 // /
136139 // / After this operation, the moved-from object is invalid.
137- RHistEngine (RHistEngine &&) = default ;
140+ RHistEngine (RHistEngine &&rhs) noexcept : fAxes (std::move(rhs. fAxes )), fBinContents (std::move(rhs. fBinContents )) {}
138141
139142 // / The copy assignment operator is deleted.
140143 // /
@@ -144,7 +147,12 @@ public:
144147 // / Efficiently move a histogram engine.
145148 // /
146149 // / After this operation, the moved-from object is invalid.
147- RHistEngine &operator =(RHistEngine &&) = default ;
150+ RHistEngine &operator =(RHistEngine &&rhs) noexcept
151+ {
152+ std::swap (fAxes , rhs.fAxes );
153+ std::swap (fBinContents , rhs.fBinContents );
154+ return *this ;
155+ }
148156
149157 ~RHistEngine () = default ;
150158
@@ -513,6 +521,10 @@ public:
513521 template <typename ... A>
514522 void FillAtomic (const std::tuple<A...> &args)
515523 {
524+ while (fSnapshot .load (std::memory_order_relaxed)) {
525+ // Spin while a snapshot is running
526+ }
527+
516528 // We could rely on RAxes::ComputeGlobalIndex to check the number of arguments, but its exception message might
517529 // be confusing for users.
518530 if (sizeof ...(A) != GetNDimensions ()) {
@@ -537,6 +549,10 @@ public:
537549 {
538550 static_assert (SupportsWeightedFilling, " weighted filling is not supported for integral bin content types" );
539551
552+ while (fSnapshot .load (std::memory_order_relaxed)) {
553+ // Spin while a snapshot is running
554+ }
555+
540556 // We could rely on RAxes::ComputeGlobalIndex to check the number of arguments, but its exception message might
541557 // be confusing for users.
542558 if (sizeof ...(A) != GetNDimensions ()) {
@@ -562,6 +578,10 @@ public:
562578 static_assert (std::is_class_v<BinContentType>,
563579 " user-defined weight types are only supported for user-defined bin content types" );
564580
581+ while (fSnapshot .load (std::memory_order_relaxed)) {
582+ // Spin while a snapshot is running
583+ }
584+
565585 // We could rely on RAxes::ComputeGlobalIndex to check the number of arguments, but its exception message might
566586 // be confusing for users.
567587 if (sizeof ...(A) != GetNDimensions ()) {
@@ -583,6 +603,10 @@ public:
583603 {
584604 static_assert (sizeof ...(A) >= 1 , " need at least one argument to Fill" );
585605 if constexpr (sizeof ...(A) >= 1 ) {
606+ while (fSnapshot .load (std::memory_order_relaxed)) {
607+ // Spin while a snapshot is running
608+ }
609+
586610 auto t = std::forward_as_tuple (args...);
587611 if constexpr (std::is_same_v<typename Internal::LastType<A...>::type, RWeight>) {
588612 static_assert (SupportsWeightedFilling, " weighted filling is not supported for integral bin content types" );
@@ -846,6 +870,12 @@ public:
846870 static_assert (std::is_trivially_copyable_v<BinContentType>,
847871 " snapshotting requires a trivially copyable bin content type" );
848872
873+ do {
874+ while (fSnapshot .load (std::memory_order_relaxed)) {
875+ // Spin while another snapshot is running
876+ }
877+ } while (fSnapshot .exchange (true , std::memory_order_relaxed));
878+
849879 RHistEngine snapshot (fAxes .Get ());
850880 // Do a first collect.
851881 for (std::size_t i = 0 ; i < fBinContents .size (); i++) {
@@ -871,6 +901,8 @@ public:
871901 }
872902 } while (changed);
873903
904+ fSnapshot .store (false , std::memory_order_relaxed);
905+
874906 return snapshot;
875907 }
876908
0 commit comments