36 #ifdef UTILS_OS_WINDOWS
37 #define UTILS_SEMAPHORE Utils::WinSemaphore
38 #define UTILS_MUTEX Utils::WinCriticalSection
39 #define UTILS_SPINLOCK Utils::WinCriticalSection
40 #define UTILS_BARRIER Utils::WinBarrier
42 #define UTILS_SEMAPHORE Utils::SimpleSemaphore
43 #define UTILS_MUTEX std::mutex
44 #define UTILS_SPINLOCK Utils::SpinLock
45 #define UTILS_BARRIER Utils::Barrier
48 #ifdef UTILS_OS_WINDOWS
56 ~WinMutex() { CloseHandle(m_mutex); }
63 class WinCriticalSection {
64 CRITICAL_SECTION m_critical;
67 { InitializeCriticalSection(&m_critical); }
68 ~WinCriticalSection() { DeleteCriticalSection(&m_critical); }
69 void lock() { EnterCriticalSection(&m_critical); }
70 void unlock() { LeaveCriticalSection(&m_critical); }
71 bool try_lock() {
return TryEnterCriticalSection(&m_critical) ? true :
false; }
72 void wait() { lock(); unlock(); }
73 CRITICAL_SECTION
const & data()
const {
return m_critical; }
74 CRITICAL_SECTION & data() {
return m_critical; }
79 WinCriticalSection m_critical;
80 CONDITION_VARIABLE m_condition;
81 unsigned m_waiting_green;
82 unsigned m_waiting_red;
85 void notify_one() noexcept { WakeConditionVariable( &m_condition ); }
86 void notify_all() noexcept { WakeAllConditionVariable( &m_condition ); }
87 void wait_cond() noexcept { SleepConditionVariableCS( &m_condition, &m_critical.data(), INFINITE ); }
95 { InitializeConditionVariable( &m_condition ); }
107 if ( m_waiting_green > 1 ) notify_all();
108 else if ( m_waiting_green > 0 ) notify_one();
119 if ( m_waiting_red > 1 ) notify_all();
120 else if ( m_waiting_red > 0 ) notify_one();
130 while ( m_is_red ) wait_cond();
142 while ( !m_is_red ) wait_cond();
151 WinCriticalSection m_critical;
152 CONDITION_VARIABLE m_condition;
155 void notify_all() noexcept { WakeAllConditionVariable( &m_condition ); }
156 void wait_cond() noexcept { SleepConditionVariableCS( &m_condition, &m_critical.data(), INFINITE ); }
159 WinBarrier() : m_to_be_done(0) {}
162 setup(
int nthreads )
163 { m_to_be_done = nthreads ; }
168 if ( --m_to_be_done <= 0 ) notify_all() ;
175 while( m_to_be_done > 0 ) wait_cond();
180 count_down_and_wait() {
182 if ( --m_to_be_done <= 0 ) {
185 while( m_to_be_done > 0 ) wait_cond();
203 std::atomic<bool> m_lock;
211 while( m_lock.load(std::memory_order_acquire) )
212 std::this_thread::yield();
217 while( m_lock.exchange(
true, std::memory_order_acquire) )
218 std::this_thread::yield();
223 return !m_lock.exchange(
true, std::memory_order_acquire);
228 m_lock.store(
false, std::memory_order_release);
242 std::atomic<unsigned> m_count;
243 std::atomic<unsigned> m_generation;
244 unsigned m_count_reset_value;
253 , m_count_reset_value(0)
258 m_count_reset_value = m_count = count ;
263 unsigned gen = m_generation.load();
264 if ( --m_count == 0 ) {
265 if ( m_generation.compare_exchange_weak(gen, gen + 1) )
266 m_count = m_count_reset_value;
273 unsigned gen = m_generation.load();
274 while ((gen == m_generation) && (m_count != 0))
275 std::this_thread::yield();
280 unsigned gen = m_generation.load();
281 if ( --m_count == 0 ) {
282 if ( m_generation.compare_exchange_weak(gen, gen + 1) )
283 m_count = m_count_reset_value;
286 while ((gen == m_generation) && (m_count != 0))
287 std::this_thread::yield();
301 std::condition_variable m_cond;
307 { m_to_be_done = nthreads ; }
311 std::unique_lock<std::mutex> lck(m_mtx);
312 if ( --m_to_be_done <= 0 ) m_cond.notify_all() ;
317 std::unique_lock<std::mutex> lck(m_mtx);
318 m_cond.wait( lck, [&]()->
bool {
return m_to_be_done <= 0; } );
323 std::unique_lock<std::mutex> lck(m_mtx);
324 if ( --m_to_be_done <= 0 ) {
325 m_cond.notify_all() ;
327 m_cond.wait( lck, [&]()->
bool {
return m_to_be_done <= 0; } );
343 unsigned m_waiting_green;
344 unsigned m_waiting_red;
346 std::condition_variable_any m_cv_red;
347 std::condition_variable_any m_cv_green;
360 std::unique_lock<std::mutex> lock( m_mutex );
362 if ( m_waiting_green > 1 ) m_cv_green.notify_all();
363 else if ( m_waiting_green > 0 ) m_cv_green.notify_one();
371 std::unique_lock<std::mutex> lock( m_mutex );
373 if ( m_waiting_red > 1 ) m_cv_red.notify_all();
374 else if ( m_waiting_red > 0 ) m_cv_red.notify_one();
382 std::unique_lock<std::mutex> lock( m_mutex );
384 while ( m_is_red ) m_cv_green.wait( m_mutex );
393 std::unique_lock<std::mutex> lock( m_mutex );
395 while ( !m_is_red ) m_cv_red.wait( m_mutex );
414 std::thread m_running_thread;
415 std::function<void()> m_job;
418 std::condition_variable m_cv;
432 void exec( std::function<
void()> & fun );
436 template <
typename Func,
typename... Args>
438 run( Func && func, Args && ... args ) {
439 std::function<void()> f = std::bind( func, std::forward<Args>(args)... );
443 std::thread::id
get_id()
const {
return m_running_thread.get_id(); }
444 std::thread
const &
get_thread()
const {
return m_running_thread; }
458 #ifdef UTILS_OS_WINDOWS
459 std::atomic<int> n_worker;
461 std::atomic<int> n_worker{0};
464 #ifdef UTILS_OS_WINDOWS
472 {
while (n_worker.load(std::memory_order_relaxed) != 0 ){} }
486 template <
typename DATA>
489 using DATA_TYPE = std::pair<std::thread::id,DATA*>;
490 mutable std::vector<DATA_TYPE> m_data;
503 for (
auto const & a : m_data )
delete a.second;
511 for (
auto const & a : m_data )
delete a.second;
512 m_data.clear(); m_data.reserve(64);
517 search( std::thread::id
const &
id,
bool & ok )
const {
519 m_worker_read.enter();
522 size_t U = m_data.size();
525 m_worker_read.leave();
527 m_worker_read.wait();
531 DATA_TYPE & dL = m_data[0];
533 DATA * res = dL.second =
new DATA();
534 m_spin_write.unlock();
540 size_t pos = (L+U)>>1;
541 std::thread::id
const & id_pos = m_data[pos].first;
542 if ( id_pos <
id ) L = pos;
else U = pos;
544 DATA_TYPE & dL = m_data[L];
545 if ( dL.first ==
id ) { m_worker_read.leave();
return dL.second; }
546 DATA_TYPE & dU = m_data[U];
547 if ( dU.first ==
id ) { m_worker_read.leave();
return dU.second; }
548 m_worker_read.leave();
552 m_worker_read.wait();
554 if ( dL.first <
id ) ++L;
559 m_data[U+1].first = m_data[U].first;
560 m_data[U+1].second = m_data[U].second;
562 DATA_TYPE & dL1 = m_data[L];
564 DATA * res = dL1.second =
new DATA();
565 m_spin_write.unlock();
583 template <
class Destructor>
585 Destructor m_destructor;
597 : m_destructor(std::forward<Destructor>(destructor))
603 : m_destructor(destructor)
608 : m_destructor(std::move(x.m_destructor))
609 , m_active(x.m_active)
610 { x.m_active =
false; }
614 m_destructor = std::move(x.m_destructor);
615 m_active = x.m_active;
640 template<
class Function>
644 template<
class Function>
657 class unique_function :
public std::function<T> {
658 template<
typename Fn,
typename En =
void>
struct wrapper;
661 template<
typename Fn>
662 struct wrapper<Fn, std::enable_if_t< std::is_copy_constructible<Fn>::value >>
665 template<
typename... Args>
666 auto operator()(Args&&... args) {
return fn(std::forward<Args>(args)...); }
670 template<
typename Fn>
671 struct wrapper<Fn, std::enable_if_t< !std::is_copy_constructible<Fn>::value && std::is_move_constructible<Fn>::value >>
675 wrapper(Fn&& fn) : fn(std::forward<Fn>(fn)) { }
677 wrapper(wrapper&&) =
default;
678 wrapper& operator=(wrapper&&) =
default;
682 wrapper(
const wrapper& rhs) : fn(const_cast<Fn&&>(rhs.fn)) {
throw 0; }
684 wrapper& operator=(wrapper&) {
throw 0;
return *
this; }
686 template<
typename... Args>
auto operator()(Args&&... args) {
return fn(std::forward<Args>(args)...); }
689 using base = std::function<T>;
692 unique_function() noexcept = default;
693 unique_function(std::nullptr_t) noexcept : base(
nullptr) { }
695 template<
typename Fn>
696 unique_function(Fn&& f) : base(wrapper<Fn>{ std::forward<Fn>(f) }) { }
698 unique_function(unique_function&&) =
default;
699 unique_function& operator=(unique_function&&) =
default;
701 unique_function& operator=(std::nullptr_t) { base::operator=(
nullptr);
return *
this; }
703 template<
typename Fn>
704 unique_function& operator=(Fn&& f)
705 { base::operator=(wrapper<Fn>{ std::forward<Fn>(f) });
return *
this; }
707 using base::operator();
void setup(int nthreads)
Definition ThreadUtils.hxx:306
Barrier()
Definition ThreadUtils.hxx:303
void count_down_and_wait()
Definition ThreadUtils.hxx:322
void wait()
Definition ThreadUtils.hxx:316
void count_down()
Definition ThreadUtils.hxx:310
void clear()
Definition ThreadUtils.hxx:509
DATA * search(std::thread::id const &id, bool &ok) const
Definition ThreadUtils.hxx:517
~BinarySearch()
Definition ThreadUtils.hxx:501
BinarySearch()
Definition ThreadUtils.hxx:496
void wait_red() noexcept
Definition ThreadUtils.hxx:392
void red() noexcept
Definition ThreadUtils.hxx:370
void green() noexcept
Definition ThreadUtils.hxx:359
SimpleSemaphore() noexcept
Definition ThreadUtils.hxx:349
void wait() noexcept
Definition ThreadUtils.hxx:381
SpinLock_barrier()
Definition ThreadUtils.hxx:250
void count_down_and_wait()
Definition ThreadUtils.hxx:279
void wait()
Definition ThreadUtils.hxx:272
SpinLock_barrier & operator=(SpinLock_barrier const &)=delete
SpinLock_barrier(SpinLock_barrier const &)=delete
void setup(unsigned count)
Definition ThreadUtils.hxx:257
void count_down()
Definition ThreadUtils.hxx:262
void lock()
Definition ThreadUtils.hxx:216
SpinLock(SpinLock const &)=delete
void unlock()
Definition ThreadUtils.hxx:227
bool try_lock()
Definition ThreadUtils.hxx:222
void wait()
Definition ThreadUtils.hxx:210
SpinLock()
Definition ThreadUtils.hxx:205
Definition ThreadUtils.hxx:456
void enter()
Definition ThreadUtils.hxx:474
void leave()
Definition ThreadUtils.hxx:475
void wait()
Definition ThreadUtils.hxx:471
WorkerLoop(WorkerLoop &&)=delete
void exec(std::function< void()> &fun)
std::thread & get_thread()
Definition ThreadUtils.hxx:445
std::thread::id get_id() const
Definition ThreadUtils.hxx:443
void run(Func &&func, Args &&... args)
Definition ThreadUtils.hxx:438
WorkerLoop(WorkerLoop const &)=delete
WorkerLoop & operator=(WorkerLoop const &)=delete
std::thread const & get_thread() const
Definition ThreadUtils.hxx:444
Definition ThreadUtils.hxx:584
at_scope_exit_impl(at_scope_exit_impl &&x) noexcept
Definition ThreadUtils.hxx:607
at_scope_exit_impl(Destructor &&destructor)
Definition ThreadUtils.hxx:596
at_scope_exit_impl(at_scope_exit_impl const &)=delete
at_scope_exit_impl(Destructor const &destructor)
Definition ThreadUtils.hxx:602
at_scope_exit_impl & operator=(at_scope_exit_impl &&x)
Definition ThreadUtils.hxx:613
~at_scope_exit_impl()
Definition ThreadUtils.hxx:620
at_scope_exit_impl()
Definition ThreadUtils.hxx:593
at_scope_exit_impl & operator=(at_scope_exit_impl const &)=delete
auto at_scope_exit(Function &&fun) -> at_scope_exit_impl< Function >
Definition ThreadUtils.hxx:641
#define UTILS_SPINLOCK
Definition ThreadUtils.hxx:44
Definition SystemUtils.cc:39
@ green
Definition rang.hxx:41
@ red
Definition rang.hxx:40