OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-cogutil commits / 9670de1

Async buffer: Wait before accepting new barrier
Wait for all workers to resume before accepting new barrier Failure to do so leads to confusion.
9670de16af94802f577c1debe8a2c0ca7d418d7c
by Linas Vepstas <linasvepstas@gmail.com> · 2025-12-07T22:50:14.000Z

Changed files (2) +56 -12

opencog/util/async_buffer.h +28 -6
……@@ -143,7 +143,7 @@ class async_buffer
143143
144144 // Barrier synchronization
145145 const Element* _current_barrier;
146 std::atomic<unsigned> _barrier_count;
146 std::atomic<int> _barrier_count;
147147
148148 void start_writer_thread();
149149 void stop_writer_threads();
……@@ -463,18 +463,33 @@ void async_buffer<Writer, Element>::barrier(const Element& elt)
463463
464464 _store_set.cancel();
465465
466 // Wait for all workers to finish processing
467 unsigned cnt = _barrier_count.load();
466 // Wait for all workers to finish processing the barrier element.
467 // Workers decrement from _thread_count+1 down to 1, then wait.
468 int cnt = _barrier_count.load();
468469 while (1 < cnt)
469470 {
470471 _barrier_count.wait(cnt);
471472 cnt = _barrier_count.load();
472473 }
473474
475 // All workers have checked in. Unblock them.
474476 _current_barrier = nullptr;
475477 _store_set.cancel_reset();
476 _barrier_count--;
478 _barrier_count--; // Now 0
477479 _barrier_count.notify_all();
480
481 // Wait for all workers to acknowledge and resume.
482 // Each worker decrements once more after waking, going negative.
483 // All workers have started when count reaches minus _thread_count
484 // Failure to wait, here, will result in confusion if another
485 // barrier arrives.
486 int target = -static_cast<int>(_thread_count);
487 cnt = _barrier_count.load();
488 while (target < cnt)
489 {
490 _barrier_count.wait(cnt);
491 cnt = _barrier_count.load();
492 }
478493}
479494
480495/// A single write thread. Reads elements from set, and invokes the
……@@ -507,18 +522,25 @@ void async_buffer<Writer, Element>::write_loop()
507522 {
508523 (_writer->*_do_write)(*_current_barrier);
509524
510 unsigned int old_count = _barrier_count.fetch_sub(1);
525 // Last one out tells the master thread.
526 int old_count = _barrier_count.fetch_sub(1);
511527 if (2 == old_count)
512528 _barrier_count.notify_all();
513529
514530 // barrier() will drop the count to zero after
515531 // all workers have run.
516 unsigned int cnt = _barrier_count.load();
532 int cnt = _barrier_count.load();
517533 while (0 < cnt)
518534 {
519535 _barrier_count.wait(cnt);
520536 cnt = _barrier_count.load();
521537 }
538
539 // Ack that we're resuming normal operation.
540 // Last one notifies the master thread.
541 old_count = _barrier_count.fetch_sub(1);
542 if (1 - static_cast<int>(_thread_count) == old_count)
543 _barrier_count.notify_all();
522544 }
523545
524546 // We are so out of here. Nothing to do, just exit this thread.
opencog/util/async_method_caller.h +28 -6
……@@ -116,7 +116,7 @@ class async_caller
116116
117117 // Barrier synchronization
118118 const Element* _current_barrier;
119 std::atomic<unsigned> _barrier_count;
119 std::atomic<int> _barrier_count;
120120
121121 void start_writer_thread();
122122 void stop_writer_threads();
……@@ -376,18 +376,33 @@ void async_caller<Writer, Element>::barrier(const Element& elt)
376376
377377 _store_queue.cancel();
378378
379 // Wait for all workers to finish processing
380 unsigned cnt = _barrier_count.load();
379 // Wait for all workers to finish processing the barrier element.
380 // Workers decrement from _thread_count+1 down to 1, then wait.
381 int cnt = _barrier_count.load();
381382 while (1 < cnt)
382383 {
383384 _barrier_count.wait(cnt);
384385 cnt = _barrier_count.load();
385386 }
386387
388 // All workers have checked in. Unblock them.
387389 _current_barrier = nullptr;
388390 _store_queue.cancel_reset();
389 _barrier_count--;
391 _barrier_count--; // Now 0
390392 _barrier_count.notify_all();
393
394 // Wait for all workers to acknowledge and resume.
395 // Each worker decrements once more after waking, going negative.
396 // All workers have started when count reaches minus _thread_count
397 // Failure to wait, here, will result in confusion if another
398 // barrier arrives.
399 int target = -static_cast<int>(_thread_count);
400 cnt = _barrier_count.load();
401 while (target < cnt)
402 {
403 _barrier_count.wait(cnt);
404 cnt = _barrier_count.load();
405 }
391406}
392407
393408/// A single write thread. Reads elements from queue, and invokes the
……@@ -414,18 +429,25 @@ void async_caller<Writer, Element>::write_loop()
414429 {
415430 (_writer->*_do_write)(*_current_barrier);
416431
417 unsigned int old_count = _barrier_count.fetch_sub(1);
432 // Last one out tells the master thread.
433 int old_count = _barrier_count.fetch_sub(1);
418434 if (2 == old_count)
419435 _barrier_count.notify_all();
420436
421437 // barrier() will drop the count to zero after
422438 // all workers have run.
423 unsigned int cnt = _barrier_count.load();
439 int cnt = _barrier_count.load();
424440 while (0 < cnt)
425441 {
426442 _barrier_count.wait(cnt);
427443 cnt = _barrier_count.load();
428444 }
445
446 // Ack that we're resuming normal operation.
447 // Last one notifies the master thread.
448 old_count = _barrier_count.fetch_sub(1);
449 if (1 - static_cast<int>(_thread_count) == old_count)
450 _barrier_count.notify_all();
429451 }
430452
431453 // We are so out of here. Nothing to do, just exit this thread.