File indexing completed on 2025-03-13 09:10:09
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #ifndef G4GMAKE
0021 #include "PTL/Config.hh" // IWYU pragma: keep
0022 #endif
0023 #include "PTL/Globals.hh"
0024 #include "PTL/VTask.hh"
0025 #if defined(PTL_USE_LOCKS)
0026 # include "PTL/AutoLock.hh"
0027 #endif
0028
0029 #include <atomic>
0030 #include <cassert>
0031 #include <list>
0032 #include <memory>
0033 #include <utility>
0034
0035 namespace PTL
0036 {
0037 class TaskSubQueue
0038 {
0039 public:
0040 template <typename Tp>
0041 using container = std::list<Tp>;
0042
0043 using task_pointer = std::shared_ptr<VTask>;
0044 using container_type = container<task_pointer>;
0045 using size_type = container_type::size_type;
0046
0047 public:
0048 TaskSubQueue(std::atomic_uintmax_t* _ntasks);
0049 TaskSubQueue(const TaskSubQueue&);
0050 ~TaskSubQueue() = default;
0051
0052 TaskSubQueue& operator=(const TaskSubQueue&) = delete;
0053
0054 public:
0055 int GetId() const;
0056
0057 bool AcquireClaim();
0058 void ReleaseClaim();
0059
0060 void PushTask(task_pointer&&) PTL_NO_SANITIZE_THREAD;
0061 task_pointer PopTask(bool front = true) PTL_NO_SANITIZE_THREAD;
0062
0063 size_type size() const;
0064 bool empty() const;
0065
0066 private:
0067
0068 #if defined(PTL_USE_LOCKS)
0069 Mutex m_mutex{};
0070 #endif
0071
0072 std::atomic<size_type> m_ntasks;
0073
0074 std::atomic_bool m_available;
0075
0076 std::atomic_uintmax_t* m_all_tasks;
0077
0078 container_type m_task_queue;
0079 };
0080
0081
0082
0083 inline TaskSubQueue::TaskSubQueue(std::atomic_uintmax_t* _ntasks)
0084 : m_ntasks(0)
0085 , m_available(true)
0086 , m_all_tasks(_ntasks)
0087 {}
0088
0089
0090
0091 inline TaskSubQueue::TaskSubQueue(const TaskSubQueue& rhs)
0092 : m_ntasks(0)
0093 , m_available(true)
0094 , m_all_tasks(rhs.m_all_tasks)
0095 {}
0096
0097
0098
0099 inline bool
0100 TaskSubQueue::AcquireClaim()
0101 {
0102 bool is_avail = m_available.load(std::memory_order_relaxed);
0103 if(!is_avail)
0104 return false;
0105 return m_available.compare_exchange_strong(is_avail, false,
0106 std::memory_order_relaxed);
0107 }
0108
0109
0110
0111 inline void
0112 TaskSubQueue::ReleaseClaim()
0113 {
0114
0115
0116 m_available.store(true, std::memory_order_release);
0117 }
0118
0119
0120
0121 inline TaskSubQueue::size_type
0122 TaskSubQueue::size() const
0123 {
0124 return m_ntasks.load();
0125 }
0126
0127
0128
0129 inline bool
0130 TaskSubQueue::empty() const
0131 {
0132 return (m_ntasks.load() == 0);
0133 }
0134
0135
0136
0137 inline void
0138 TaskSubQueue::PushTask(task_pointer&& task)
0139 {
0140
0141 assert(m_available.load(std::memory_order_relaxed) == false);
0142 ++m_ntasks;
0143 #if defined(PTL_USE_LOCKS)
0144 AutoLock lk{ m_mutex };
0145 #endif
0146 m_task_queue.emplace_front(std::move(task));
0147 }
0148
0149
0150
0151 inline TaskSubQueue::task_pointer
0152 TaskSubQueue::PopTask(bool front)
0153 {
0154
0155 assert(m_available.load(std::memory_order_relaxed) == false);
0156 if(m_ntasks.load() == 0)
0157 return nullptr;
0158
0159 task_pointer _task{ nullptr };
0160 if(front)
0161 {
0162 #if defined(PTL_USE_LOCKS)
0163 AutoLock lk{ m_mutex };
0164 #endif
0165 _task = std::move(m_task_queue.front());
0166 m_task_queue.pop_front();
0167 }
0168 else
0169 {
0170 #if defined(PTL_USE_LOCKS)
0171 AutoLock lk{ m_mutex };
0172 #endif
0173 _task = std::move(m_task_queue.back());
0174 m_task_queue.pop_back();
0175 }
0176 --m_ntasks;
0177
0178 return _task;
0179 }
0180
0181
0182 }