Geant4 Cross Reference |
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 // Tasking class header 21 // Class Description: 22 // --------------------------------------------------------------- 23 // Author: Jonathan Madsen 24 // --------------------------------------------------------------- 25 26 #pragma once 27 28 #include "PTL/Macros.hh" 29 #include "PTL/TaskSubQueue.hh" 30 #include "PTL/Types.hh" 31 #include "PTL/VUserTaskQueue.hh" 32 33 #include <atomic> 34 #include <cstdint> 35 #include <memory> 36 #include <random> 37 #include <vector> 38 39 namespace PTL 40 { 41 class ThreadData; 42 class ThreadPool; 43 class VTask; 44 45 class UserTaskQueue : public VUserTaskQueue 46 { 47 public: 48 using task_pointer = std::shared_ptr<VTask>; 49 using TaskSubQueueContainer = std::vector<TaskSubQueue*>; 50 using random_engine_t = std::default_random_engine; 51 using int_dist_t = std::uniform_int_distribution<int>; 52 53 public: 54 // Constructor and Destructors 55 UserTaskQueue(intmax_t nworkers = -1, UserTaskQueue* = nullptr); 56 // Virtual destructors are required by abstract classes 57 // so add it by default, just in case 58 ~UserTaskQueue() override; 59 60 public: 61 // Virtual function for getting a task from the queue 62 task_pointer GetTask(intmax_t subq = -1, intmax_t nitr = -1) override; 63 // Virtual function for inserting a task into the queue 64 intmax_t InsertTask(task_pointer&&, ThreadData* = nullptr, 65 intmax_t subq = -1) override PTL_NO_SANITIZE_THREAD; 66 67 // if executing only tasks in threads bin 68 task_pointer GetThreadBinTask(); 69 70 // Overload this function to hold threads 71 void Wait() override {} 72 void resize(intmax_t) override; 73 74 bool empty() const override; 75 size_type size() const override; 76 77 size_type bin_size(size_type bin) const override; 78 bool bin_empty(size_type bin) const override; 79 80 bool true_empty() const override; 81 size_type true_size() const override; 82 83 void ExecuteOnAllThreads(ThreadPool* tp, function_type f) override; 84 85 void ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp, 86 function_type f) override; 87 88 VUserTaskQueue* clone() override; 89 90 intmax_t GetThreadBin() const override; 91 92 protected: 93 intmax_t GetInsertBin() const; 94 95 private: 96 void AcquireHold(); 97 void ReleaseHold(); 98 99 private: 100 bool m_is_clone; 101 intmax_t m_thread_bin; 102 mutable intmax_t m_insert_bin; 103 std::atomic_bool* m_hold = nullptr; 104 std::atomic_uintmax_t* m_ntasks = nullptr; 105 Mutex* m_mutex = nullptr; 106 TaskSubQueueContainer* m_subqueues = nullptr; 107 std::vector<int> m_rand_list = {}; 108 std::vector<int>::iterator m_rand_itr = {}; 109 }; 110 111 //======================================================================================// 112 113 inline bool 114 UserTaskQueue::empty() const 115 { 116 return (m_ntasks->load(std::memory_order_relaxed) == 0); 117 } 118 119 //======================================================================================// 120 121 inline UserTaskQueue::size_type 122 UserTaskQueue::size() const 123 { 124 return m_ntasks->load(std::memory_order_relaxed); 125 } 126 127 //======================================================================================// 128 129 inline UserTaskQueue::size_type 130 UserTaskQueue::bin_size(size_type bin) const 131 { 132 return (*m_subqueues)[bin]->size(); 133 } 134 135 //======================================================================================// 136 137 inline bool 138 UserTaskQueue::bin_empty(size_type bin) const 139 { 140 return (*m_subqueues)[bin]->empty(); 141 } 142 143 //======================================================================================// 144 145 inline bool 146 UserTaskQueue::true_empty() const 147 { 148 for(const auto& itr : *m_subqueues) 149 if(!itr->empty()) 150 return false; 151 return true; 152 } 153 154 //======================================================================================// 155 156 inline UserTaskQueue::size_type 157 UserTaskQueue::true_size() const 158 { 159 size_type _n = 0; 160 for(const auto& itr : *m_subqueues) 161 _n += itr->size(); 162 return _n; 163 } 164 165 //======================================================================================// 166 } // namespace PTL 167