-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paththread.h
105 lines (88 loc) · 3.61 KB
/
thread.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/** \file thread.h
* \author Andrej Leban
* \date 3/2020
*
* Concurrency primitives and helpers.
*/
#ifndef CM_THREAD_H
#define CM_THREAD_H
#include <atomic>
#include <condition_variable>
#include <functional>
#include <thread>
namespace cm
{
//! \brief A simple barrier using a busy wait.
class SpinLockBarrier
{
public:
//! \brief SpinLockBarrier
//! \param p_nThreads - The number of participating threads.
explicit SpinLockBarrier(unsigned p_nThreads);
SpinLockBarrier(const SpinLockBarrier &) = delete;
SpinLockBarrier & operator=(const SpinLockBarrier &) = delete;
~SpinLockBarrier() = default;
//! \brief The current thread blocks until all \a m_nThreads have arrived at the same point.
void arrive_and_wait() noexcept;
//! \brief The current thread is counted as having arrived at the barrier, then drops out,
//! thereby no longer being counted as participating.
//! NOTE: The user is required to ensure on the call-side that the thread no longer arrives at the barrier afterwards.
void arrive_and_drop() noexcept;
protected:
std::atomic_uint m_nThreads;
std::atomic_uint m_counter;
std::atomic_ulong m_numResets{0};
};
//! \brief A synchronization barrier.
//! Implementation of std::experimental::barrier.
class Barrier : public SpinLockBarrier
{
public:
//! \brief Barrier
//! \param p_nThreads - The number of participating threads.
explicit Barrier(unsigned p_nThreads);
Barrier(const Barrier &) = delete;
Barrier & operator=(const Barrier &) = delete;
~Barrier() = default;
//! \brief The current thread blocks until all \a m_nThreads have arrived at the same point.
void arrive_and_wait() noexcept;
//! \brief The current thread is counted as having arrived at the barrier, then drops out,
//! thereby no longer being counted as participating.
//! NOTE: The user is required to ensure on the call-side that the thread no longer arrives at the barrier afterwards.
void arrive_and_drop() noexcept;
protected:
std::condition_variable m_condvar{};
mutable std::mutex m_mutex{};
};
//! \brief A synchronization barrier with an optional callable that is called after each synchronization.
//! Implementation of std::experimental::flex_barrier.
//! The signature of the callable is std::ptrdiff_t (void), where the return value signifies the new number of participating
//! threads. If the return is -1, the number remains unchanged.
class FlexBarrier : public Barrier
{
public:
using comp_func = std::function<std::ptrdiff_t()>;
//! \brief FlexBarrier
//! \param p_nThreads - The number of participating threads.
explicit FlexBarrier(unsigned p_nThreads);
//! \brief FlexBarrier
//! \param p_nThreads - The number of participating threads.
//! \param p_func - Custom callable invoked at each synchronization.
FlexBarrier(unsigned p_nThreads, comp_func p_func);
FlexBarrier(const FlexBarrier &) = delete;
FlexBarrier & operator=(const FlexBarrier &) = delete;
~FlexBarrier() = default;
//! \brief The current thread blocks until all \a m_nThreads have arrived at the same point.
void arrive_and_wait() noexcept;
//! \brief The current thread is counted as having arrived at the barrier, then drops out,
//! thereby no longer being counted as participating.
//! NOTE: The user is required to ensure on the call-side that the thread no longer arrives at the barrier afterwards.
void arrive_and_drop() noexcept;
unsigned numThreads() const { return m_nThreads; }
protected:
comp_func m_func;
private:
void release() noexcept;
};
} // namespace cm
#endif // CM_THREAD_H