Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ba96c4e

Browse files
Merge branch 'dev'
2 parents 56106af + 875404c commit ba96c4e

File tree

2 files changed

+49
-22
lines changed

2 files changed

+49
-22
lines changed

taskflow/executor/workstealing.hpp

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// 2019/04/19 - modified by Tsung-Wei Huang
2+
// - added delay yielding strategy
3+
// - added mailbox strategy to balance the wakeup calls
4+
// - TODO: need to add mailbox strategy to batch
5+
// - TODO: need a notify_n to wake up n threads
6+
// - TODO: can we skip the --mailbox in emplace?
7+
//
18
// 2019/04/11 - modified by Tsung-Wei Huang
29
// - renamed to executor
310
//
@@ -320,6 +327,7 @@ class WorkStealingExecutor {
320327

321328
struct Worker {
322329
std::minstd_rand rdgen { std::random_device{}() };
330+
std::atomic<size_t> mailbox {0};
323331
std::optional<Closure> cache;
324332
WorkStealingQueue<Closure> queue;
325333
};
@@ -437,16 +445,6 @@ WorkStealingExecutor<Closure>::WorkStealingExecutor(unsigned N) :
437445
_workers {N},
438446
_waiters {N},
439447
_notifier {_waiters} {
440-
441-
//for(unsigned i = 1; i <= N; i++) {
442-
// unsigned a = i;
443-
// unsigned b = N;
444-
// // If GCD(a, b) == 1, then a and b are coprimes.
445-
// if(std::gcd(a, b) == 1) {
446-
// _coprimes.push_back(i);
447-
// }
448-
//}
449-
450448
_spawn(N);
451449
}
452450

@@ -533,17 +531,10 @@ size_t WorkStealingExecutor<Closure>::num_workers() const {
533531
return _workers.size();
534532
}
535533

536-
// Function: _non_empty_queue
534+
// Function: _find_victim
537535
template <typename Closure>
538536
unsigned WorkStealingExecutor<Closure>::_find_victim(unsigned thief) {
539537

540-
//assert(_workers[thief].queue.empty());
541-
542-
//auto &pt = _per_thread();
543-
//auto rnd = _randomize(pt.seed);
544-
//auto inc = _coprimes[_fast_modulo(rnd, _coprimes.size())];
545-
//auto vtm = _fast_modulo(rnd, _workers.size());
546-
547538
unsigned l = 0;
548539
unsigned r = _workers.size() - 1;
549540
unsigned vtm = std::uniform_int_distribution<unsigned>{l, r}(
@@ -587,11 +578,21 @@ void WorkStealingExecutor<Closure>::_explore_task(
587578

588579
if(auto vtm = _find_victim(thief); vtm != _workers.size()) {
589580
t = (vtm == thief) ? _queue.steal() : _workers[vtm].queue.steal();
581+
// successful thief
590582
if(t) {
591583
return;
592584
}
585+
// wasteful thief
586+
else if(vtm != thief) {
587+
size_t C = _workers[vtm].mailbox.load(std::memory_order_acquire);
588+
if(C && _workers[vtm].mailbox.compare_exchange_strong(C, C-1,
589+
std::memory_order_seq_cst,
590+
std::memory_order_relaxed)) {
591+
_notifier.notify(false);
592+
}
593+
}
593594
}
594-
595+
595596
if(num_failures++ > max_failures) {
596597
num_failures = 0;
597598
if(std::this_thread::yield(); num_yields++ > max_yields) {
@@ -659,7 +660,22 @@ bool WorkStealingExecutor<Closure>::_wait_for_tasks(
659660
_notifier.notify(true);
660661
return false;
661662
}
663+
664+
// After we update the idler count, we need to check the mailbox
665+
// again to ensure there is no new wakeup requests.
666+
for(unsigned w = 0; w<_workers.size(); ++w) {
667+
if(w == me) {
668+
_workers[w].mailbox.store(0, std::memory_order_relaxed);
669+
continue;
670+
}
671+
else if(_workers[w].mailbox != 0) {
672+
_notifier.cancel_wait(&_waiters[me]);
673+
--_num_idlers;
674+
return true;
675+
}
676+
}
662677

678+
// Now I really need to relinguish my self to others
663679
_notifier.commit_wait(&_waiters[me]);
664680
--_num_idlers;
665681

@@ -687,6 +703,16 @@ void WorkStealingExecutor<Closure>::emplace(ArgsT&&... args){
687703
}
688704
else {
689705
_workers[pt.worker_id].queue.push(Closure{std::forward<ArgsT>(args)...});
706+
707+
// We only do the wake-up when this thread is the only worker!
708+
// Notice that incrementing the mailbox should come before if-statement.
709+
++_workers[pt.worker_id].mailbox;
710+
if(_num_idlers != num_workers() - 1) {
711+
return;
712+
}
713+
else {
714+
_workers[pt.worker_id].mailbox--;
715+
}
690716
}
691717
}
692718
// other threads
@@ -723,7 +749,8 @@ void WorkStealingExecutor<Closure>::batch(std::vector<Closure>& tasks) {
723749
if(!_workers[pt.worker_id].cache) {
724750
_workers[pt.worker_id].cache = std::move(tasks[i++]);
725751
}
726-
752+
753+
// TODO: need to implement the mailbox strategy as well
727754
for(; i<tasks.size(); ++i) {
728755
_workers[pt.worker_id].queue.push(std::move(tasks[i]));
729756
_notifier.notify(false);

taskflow/utility/backoff.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ namespace tf {
5555
# endif
5656
#else
5757
# define cpu_relax() { \
58-
static constexpr std::chrono::microseconds us0{ 0 }; \
59-
std::this_thread::sleep_for(us0); \
58+
static constexpr std::chrono::microseconds us0{ 0 }; \
59+
std::this_thread::sleep_for(us0); \
6060
}
6161
#endif
6262

0 commit comments

Comments
 (0)