@@ -131,22 +131,22 @@ class gil_safe_call_once_and_store {
131131 gil_scoped_release gil_rel; // Needed to establish lock ordering.
132132 {
133133 detail::with_internals ([&](detail::internals &internals) {
134- // The concurrency control is done inside `detail::with_internals`.
135- // At most one thread will enter here at a time.
136- const void *k = reinterpret_cast <const void *>(this );
134+ const void *key = reinterpret_cast <const void *>(this );
137135 auto &storage_map = internals.call_once_storage_map ;
138- // There can be multiple threads going through here, but only one each at a
139- // time. So only one thread will create the storage. Other threads will find it
140- // already created.
141- auto it = storage_map.find (k);
142- if (it == storage_map.end ()) {
136+ // There can be multiple threads going through here.
137+ if (storage_map.find (key) == storage_map.end ()) {
143138 gil_scoped_acquire gil_acq;
144- auto v = new detail::call_once_storage<T>{};
145- ::new (v->storage ) T (fn ()); // fn may release, but will reacquire, the GIL.
146- v->finalize = finalize_fn;
147- last_storage_ptr_ = reinterpret_cast <T *>(v->storage );
148- v->is_initialized = true ;
149- storage_map.emplace (k, v);
139+ // Only one thread will enter here at a time.
140+ // Fast recheck to avoid double work.
141+ if (storage_map.find (key) == storage_map.end ()) {
142+ auto value = new detail::call_once_storage<T>{};
143+ // fn may release, but will reacquire, the GIL.
144+ ::new (value->storage ) T (fn ());
145+ value->finalize = finalize_fn;
146+ value->is_initialized = true ;
147+ storage_map.emplace (key, value);
148+ last_storage_ptr_ = reinterpret_cast <T *>(value->storage );
149+ }
150150 }
151151 is_initialized_by_atleast_one_interpreter_ = true ;
152152 });
0 commit comments