@@ -37,7 +37,6 @@ namespace detail {
37
37
struct LIBASYNC_CACHELINE_ALIGN thread_data_t {
38
38
work_steal_queue queue;
39
39
std::minstd_rand rng;
40
- task_wait_event event;
41
40
std::thread handle;
42
41
};
43
42
@@ -180,11 +179,15 @@ static void thread_task_loop(threadpool_data* impl, std::size_t thread_id, task_
180
179
// Flag indicating if we have added a continuation to the task
181
180
bool added_continuation = false ;
182
181
182
+ // Event to wait on
183
+ task_wait_event event;
184
+
183
185
// Loop while waiting for the task to complete
184
186
while (true ) {
185
187
// Check if the task has finished. If we have added a continuation, we
186
- // need to make sure the event has been signaled.
187
- if (wait_task && (added_continuation ? current_thread.event .try_wait (wait_type::task_finished) : wait_task.ready ()))
188
+ // need to make sure the event has been signaled, otherwise the other
189
+ // thread may try to signal it after we have freed it.
190
+ if (wait_task && (added_continuation ? event.try_wait (wait_type::task_finished) : wait_task.ready ()))
188
191
return ;
189
192
190
193
// Try to get a task from the local queue
@@ -220,11 +223,13 @@ static void thread_task_loop(threadpool_data* impl, std::size_t thread_id, task_
220
223
return ;
221
224
}
222
225
226
+ // Initialize the event object
227
+ event.init ();
228
+
223
229
// No tasks found, so sleep until something happens.
224
230
// If a continuation has not been added yet, add it.
225
231
if (wait_task && !added_continuation) {
226
232
// Create a continuation for the task we are waiting for
227
- task_wait_event& event = current_thread.event ;
228
233
wait_task.on_finish ([&event] {
229
234
// Signal the thread's event
230
235
event.signal (wait_type::task_finished);
@@ -234,27 +239,29 @@ static void thread_task_loop(threadpool_data* impl, std::size_t thread_id, task_
234
239
235
240
// Add our thread to the list of waiting threads
236
241
size_t num_waiters_val = impl->num_waiters .load (std::memory_order_relaxed);
237
- impl->waiters [num_waiters_val] = ¤t_thread. event ;
242
+ impl->waiters [num_waiters_val] = &event;
238
243
impl->num_waiters .store (num_waiters_val + 1 , std::memory_order_relaxed);
239
244
240
245
// Wait for our event to be signaled when a task is scheduled or
241
246
// the task we are waiting for has completed.
242
247
locked.unlock ();
243
- int events = current_thread. event .wait ();
248
+ int events = event.wait ();
244
249
locked.lock ();
245
250
246
251
// Remove our thread from the list of waiting threads
247
252
num_waiters_val = impl->num_waiters .load (std::memory_order_relaxed);
248
253
for (std::size_t i = 0 ; i < num_waiters_val; i++) {
249
- if (impl->waiters [i] == ¤t_thread. event ) {
254
+ if (impl->waiters [i] == &event) {
250
255
if (i != num_waiters_val - 1 )
251
256
std::swap (impl->waiters [i], impl->waiters [num_waiters_val - 1 ]);
252
257
impl->num_waiters .store (num_waiters_val - 1 , std::memory_order_relaxed);
253
258
break ;
254
259
}
255
260
}
256
261
257
- // Check again if the task has finished
262
+ // Check again if the task has finished. We have added a
263
+ // continuation at this point, so we need to check that the
264
+ // continuation has finished signaling the event.
258
265
if (wait_task && (events & wait_type::task_finished))
259
266
return ;
260
267
}
0 commit comments