@@ -142,6 +142,12 @@ namespace experimental::execution
142142 std::size_t index_{(std::numeric_limits<std::size_t >::max)()};
143143 };
144144
145+ enum class remote_poll_mode
146+ {
147+ speculative,
148+ before_sleep
149+ };
150+
145151 struct remote_queue_list
146152 {
147153 private:
@@ -168,13 +174,18 @@ namespace experimental::execution
168174 }
169175 }
170176
171- auto pop_all_reversed (std::size_t tid) noexcept -> __intrusive_queue<&task_base::next_>
177+ auto pop_all_reversed (std::size_t tid, remote_poll_mode mode) noexcept
178+ -> __intrusive_queue<&task_base::next_>
172179 {
173180 remote_queue* head = head_.load (__std::memory_order_acquire);
174181 __intrusive_queue<&task_base::next_> tasks{};
175182 while (head != nullptr )
176183 {
177- tasks.append (head->queues_ [tid].pop_all_reversed ());
184+ auto & queue = head->queues_ [tid];
185+ if (mode == remote_poll_mode::before_sleep || !queue.empty ())
186+ {
187+ tasks.append (queue.pop_all_reversed ());
188+ }
178189 head = head->next_ ;
179190 }
180191 return tasks;
@@ -648,7 +659,7 @@ namespace experimental::execution
648659 };
649660
650661 auto try_pop () -> pop_result;
651- auto try_remote () -> pop_result;
662+ auto try_remote (remote_poll_mode mode ) -> pop_result;
652663 auto try_steal (std::span<workstealing_victim> victims) -> pop_result;
653664 auto try_steal_near () -> pop_result;
654665 auto try_steal_any () -> pop_result;
@@ -973,11 +984,11 @@ namespace experimental::execution
973984 tmp.clear ();
974985 }
975986
976- inline auto
977- _static_thread_pool::thread_state::try_remote () -> _static_thread_pool::thread_state::pop_result
987+ inline auto _static_thread_pool::thread_state::try_remote (remote_poll_mode mode)
988+ -> _static_thread_pool::thread_state::pop_result
978989 {
979990 pop_result result{.task = nullptr , .queue_index = index_};
980- __intrusive_queue<&task_base::next_> remotes = pool_->remotes_ .pop_all_reversed (index_);
991+ __intrusive_queue<&task_base::next_> remotes = pool_->remotes_ .pop_all_reversed (index_, mode );
981992 pending_queue_.append (std::move (remotes));
982993 if (!pending_queue_.empty ())
983994 {
@@ -997,7 +1008,7 @@ namespace experimental::execution
9971008 {
9981009 return result;
9991010 }
1000- return try_remote ();
1011+ return try_remote (remote_poll_mode::speculative );
10011012 }
10021013
10031014 inline auto _static_thread_pool::thread_state::try_steal (std::span<workstealing_victim> victims)
@@ -1130,11 +1141,22 @@ namespace experimental::execution
11301141 return result;
11311142 }
11321143 state expected = state::running;
1133- if (state_.compare_exchange_weak (expected, state::sleeping, __std::memory_order_relaxed))
1134- {
1135- result = try_remote ();
1144+ if (state_.compare_exchange_weak (expected,
1145+ state::sleeping,
1146+ __std::memory_order_relaxed,
1147+ __std::memory_order_relaxed))
1148+ {
1149+ // The relaxed empty probe is safe during normal polling, but the
1150+ // running-to-sleeping boundary must perform the CAS dequeue so work
1151+ // published before the transition cannot be missed.
1152+ result = try_remote (remote_poll_mode::before_sleep);
11361153 if (result.task )
11371154 {
1155+ state expected_sleeping = state::sleeping;
1156+ state_.compare_exchange_strong (expected_sleeping,
1157+ state::running,
1158+ __std::memory_order_relaxed,
1159+ __std::memory_order_relaxed);
11381160 return result;
11391161 }
11401162 set_sleeping ();
@@ -1146,15 +1168,15 @@ namespace experimental::execution
11461168 {
11471169 lock.unlock ();
11481170 }
1149- state_.store (state::running, __std::memory_order_relaxed );
1171+ state_.exchange (state::running, __std::memory_order_acquire );
11501172 result = try_pop ();
11511173 }
11521174 return result;
11531175 }
11541176
11551177 inline auto _static_thread_pool::thread_state::notify () -> bool
11561178 {
1157- if (state_.exchange (state::notified, __std::memory_order_relaxed ) == state::sleeping)
1179+ if (state_.exchange (state::notified, __std::memory_order_release ) == state::sleeping)
11581180 {
11591181 {
11601182 std::lock_guard lock{mut_};
0 commit comments