Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
TaskSubQueue.hh
Go to the documentation of this file.
1//
2// MIT License
3// Copyright (c) 2020 Jonathan R. Madsen
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
12// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
13// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
16// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
17// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18//
19
20#ifndef G4GMAKE
21#include "PTL/Config.hh" // IWYU pragma: keep
22#endif
23#include "PTL/Globals.hh"
24#include "PTL/VTask.hh"
25#if defined(PTL_USE_LOCKS)
26# include "PTL/AutoLock.hh"
27#endif
28
29#include <atomic>
30#include <cassert>
31#include <list>
32#include <memory>
33#include <utility>
34
35namespace PTL
36{
38{
39public:
40 template <typename Tp>
41 using container = std::list<Tp>;
42
43 using task_pointer = std::shared_ptr<VTask>;
45 using size_type = container_type::size_type;
46
47public:
48 TaskSubQueue(std::atomic_uintmax_t* _ntasks);
50 ~TaskSubQueue() = default;
51
53
54public:
55 int GetId() const;
56
57 bool AcquireClaim();
58 void ReleaseClaim();
59
62
63 size_type size() const;
64 bool empty() const;
65
66private:
67 // mutex
68#if defined(PTL_USE_LOCKS)
69 Mutex m_mutex{};
70#endif
71 // used internally to keep number of tasks
72 std::atomic<size_type> m_ntasks;
73 // for checking if being modified
74 std::atomic_bool m_available;
75 // used my master queue to keep track of number of tasks
76 std::atomic_uintmax_t* m_all_tasks;
77 // queue of tasks
78 container_type m_task_queue;
79};
80
81//======================================================================================//
82
83inline TaskSubQueue::TaskSubQueue(std::atomic_uintmax_t* _ntasks)
84: m_ntasks(0)
85, m_available(true)
86, m_all_tasks(_ntasks)
87{}
88
89//======================================================================================//
90
92: m_ntasks(0)
93, m_available(true)
94, m_all_tasks(rhs.m_all_tasks)
95{}
96
97//======================================================================================//
98
99inline bool
101{
102 bool is_avail = m_available.load(std::memory_order_relaxed);
103 if(!is_avail)
104 return false;
105 return m_available.compare_exchange_strong(is_avail, false,
106 std::memory_order_relaxed);
107}
108
109//======================================================================================//
110
111inline void
113{
114 // if(m_available.load(std::memory_order_relaxed))
115 // return;
116 m_available.store(true, std::memory_order_release);
117}
118
119//======================================================================================//
120
123{
124 return m_ntasks.load();
125}
126
127//======================================================================================//
128
129inline bool
131{
132 return (m_ntasks.load() == 0);
133}
134
135//======================================================================================//
136
137inline void
139{
140 // no need to lock these if claim is acquired via atomic
141 assert(m_available.load(std::memory_order_relaxed) == false);
142 ++m_ntasks;
143#if defined(PTL_USE_LOCKS)
144 AutoLock lk{ m_mutex };
145#endif
146 m_task_queue.emplace_front(std::move(task));
147}
148
149//======================================================================================//
150
153{
154 // no need to lock -- claim is acquired via atomic
155 assert(m_available.load(std::memory_order_relaxed) == false);
156 if(m_ntasks.load() == 0)
157 return nullptr;
158
159 task_pointer _task{ nullptr };
160 if(front)
161 {
162#if defined(PTL_USE_LOCKS)
163 AutoLock lk{ m_mutex };
164#endif
165 _task = std::move(m_task_queue.front());
166 m_task_queue.pop_front();
167 }
168 else
169 {
170#if defined(PTL_USE_LOCKS)
171 AutoLock lk{ m_mutex };
172#endif
173 _task = std::move(m_task_queue.back());
174 m_task_queue.pop_back();
175 }
176 --m_ntasks;
177
178 return _task;
179}
180
181//======================================================================================//
182} // namespace PTL
#define PTL_NO_SANITIZE_THREAD
Definition Globals.hh:47
container_type::size_type size_type
container< task_pointer > container_type
void PushTask(task_pointer &&) PTL_NO_SANITIZE_THREAD
int GetId() const
TaskSubQueue & operator=(const TaskSubQueue &)=delete
TaskSubQueue(std::atomic_uintmax_t *_ntasks)
~TaskSubQueue()=default
size_type size() const
task_pointer PopTask(bool front=true) PTL_NO_SANITIZE_THREAD
bool empty() const
std::list< Tp > container
std::shared_ptr< VTask > task_pointer
std::mutex Mutex
Definition Threading.hh:57