Import Geant4 11.0.0.beta source tree
This commit is contained in:
-129
@@ -1,129 +0,0 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2020 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// ---------------------------------------------------------------
|
||||
// Tasking class implementation
|
||||
//
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include "PTL/TaskAllocator.hh"
|
||||
#include "PTL/TaskAllocatorList.hh"
|
||||
|
||||
using namespace PTL;
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskAllocatorList*&
|
||||
TaskAllocatorList::fAllocatorList()
|
||||
{
|
||||
static thread_local TaskAllocatorList* _instance = nullptr;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskAllocatorList*
|
||||
TaskAllocatorList::GetAllocatorList()
|
||||
{
|
||||
if(!fAllocatorList())
|
||||
{
|
||||
fAllocatorList() = new TaskAllocatorList;
|
||||
}
|
||||
return fAllocatorList();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskAllocatorList*
|
||||
TaskAllocatorList::GetAllocatorListIfExist()
|
||||
{
|
||||
return fAllocatorList();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskAllocatorList::TaskAllocatorList() {}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskAllocatorList::~TaskAllocatorList() { fAllocatorList() = nullptr; }
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
TaskAllocatorList::Register(TaskAllocatorBase* alloc)
|
||||
{
|
||||
fList.push_back(alloc);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
TaskAllocatorList::Destroy(int nStat, int verboseLevel)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
double tmem = 0;
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
std::cout << "================== Deleting memory pools ==================="
|
||||
<< std::endl;
|
||||
}
|
||||
for(auto& itr : fList)
|
||||
{
|
||||
double mem = itr->GetAllocatedSize();
|
||||
if(i < nStat)
|
||||
{
|
||||
i++;
|
||||
tmem += mem;
|
||||
itr->ResetStorage();
|
||||
continue;
|
||||
}
|
||||
j++;
|
||||
tmem += mem;
|
||||
if(verboseLevel > 1)
|
||||
{
|
||||
std::cout << "Pool ID '" << itr->GetPoolType()
|
||||
<< "', size : " << std::setprecision(3) << mem / 1048576
|
||||
<< std::setprecision(6) << " MB" << std::endl;
|
||||
}
|
||||
itr->ResetStorage();
|
||||
// delete *itr;
|
||||
}
|
||||
if(verboseLevel > 0)
|
||||
{
|
||||
std::cout << "Number of memory pools allocated: " << Size()
|
||||
<< "; of which, static: " << i << std::endl;
|
||||
std::cout << "Dynamic pools deleted: " << j
|
||||
<< " / Total memory freed: " << std::setprecision(2) << tmem / 1048576
|
||||
<< std::setprecision(6) << " MB" << std::endl;
|
||||
std::cout << "============================================================"
|
||||
<< std::endl;
|
||||
}
|
||||
fList.clear();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
int
|
||||
TaskAllocatorList::Size() const
|
||||
{
|
||||
return fList.size();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2020 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// ---------------------------------------------------------------
|
||||
// Tasking class implementation
|
||||
//
|
||||
// TaskAllocatorPool
|
||||
//
|
||||
// Implementation file
|
||||
//
|
||||
// Author: G.Cosmo, November 2000
|
||||
//
|
||||
|
||||
#include "PTL/TaskAllocatorPool.hh"
|
||||
|
||||
using namespace PTL;
|
||||
|
||||
// ************************************************************
|
||||
// TaskAllocatorPool constructor
|
||||
// ************************************************************
|
||||
//
|
||||
TaskAllocatorPool::TaskAllocatorPool(unsigned int sz)
|
||||
: esize((sz < sizeof(PoolLink)) ? sizeof(PoolLink) : sz)
|
||||
, csize((sz < 1024 / 2 - 16) ? (1024 - 16) : (sz * 10 - 16))
|
||||
, chunks(nullptr)
|
||||
, head(nullptr)
|
||||
, nchunks(0)
|
||||
{}
|
||||
|
||||
// ************************************************************
|
||||
// TaskAllocatorPool copy constructor
|
||||
// ************************************************************
|
||||
//
|
||||
TaskAllocatorPool::TaskAllocatorPool(const TaskAllocatorPool& right)
|
||||
: esize(right.esize)
|
||||
, csize(right.csize)
|
||||
, chunks(right.chunks)
|
||||
, head(right.head)
|
||||
, nchunks(right.nchunks)
|
||||
{}
|
||||
|
||||
// ************************************************************
|
||||
// TaskAllocatorPool operator=
|
||||
// ************************************************************
|
||||
//
|
||||
TaskAllocatorPool&
|
||||
TaskAllocatorPool::operator=(const TaskAllocatorPool& right)
|
||||
{
|
||||
if(&right == this)
|
||||
return *this;
|
||||
chunks = right.chunks;
|
||||
head = right.head;
|
||||
nchunks = right.nchunks;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// TaskAllocatorPool destructor
|
||||
// ************************************************************
|
||||
//
|
||||
TaskAllocatorPool::~TaskAllocatorPool() { Reset(); }
|
||||
|
||||
// ************************************************************
|
||||
// Reset
|
||||
// ************************************************************
|
||||
//
|
||||
void
|
||||
TaskAllocatorPool::Reset()
|
||||
{
|
||||
// Free all chunks
|
||||
//
|
||||
PoolChunk* n = chunks;
|
||||
PoolChunk* p = nullptr;
|
||||
while(n)
|
||||
{
|
||||
p = n;
|
||||
n = n->next;
|
||||
delete p;
|
||||
}
|
||||
head = nullptr;
|
||||
chunks = nullptr;
|
||||
nchunks = 0;
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// Grow
|
||||
// ************************************************************
|
||||
//
|
||||
void
|
||||
TaskAllocatorPool::Grow()
|
||||
{
|
||||
// Allocate new chunk, organize it as a linked list of
|
||||
// elements of size 'esize'
|
||||
//
|
||||
PoolChunk* n = new PoolChunk(csize);
|
||||
n->next = chunks;
|
||||
chunks = n;
|
||||
nchunks++;
|
||||
|
||||
const int nelem = csize / esize;
|
||||
char* start = n->mem;
|
||||
char* last = &start[(nelem - 1) * esize];
|
||||
for(char* p = start; p < last; p += esize)
|
||||
{
|
||||
reinterpret_cast<PoolLink*>(p)->next = reinterpret_cast<PoolLink*>(p + esize);
|
||||
}
|
||||
reinterpret_cast<PoolLink*>(last)->next = nullptr;
|
||||
head = reinterpret_cast<PoolLink*>(start);
|
||||
}
|
||||
+36
-8
@@ -19,22 +19,50 @@
|
||||
// ---------------------------------------------------------------
|
||||
// Tasking class implementation
|
||||
//
|
||||
// Class Description:
|
||||
//
|
||||
// This file creates an abstract base class for the grouping the thread-pool
|
||||
// tasking system into independently joinable units
|
||||
//
|
||||
// ---------------------------------------------------------------
|
||||
// Author: Jonathan Madsen (Feb 13th 2018)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
#include "PTL/TaskAllocator.hh"
|
||||
#include "PTL/TaskAllocatorList.hh"
|
||||
|
||||
using namespace PTL;
|
||||
#include "PTL/TaskGroup.hh"
|
||||
#include "PTL/Globals.hh"
|
||||
#include "PTL/Task.hh"
|
||||
#include "PTL/TaskRunManager.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "PTL/VTask.hh"
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskAllocatorBase::TaskAllocatorBase()
|
||||
namespace PTL
|
||||
{
|
||||
TaskAllocatorList::GetAllocatorList()->Register(this);
|
||||
namespace internal
|
||||
{
|
||||
std::atomic_uintmax_t&
|
||||
task_group_counter()
|
||||
{
|
||||
static std::atomic_uintmax_t _instance(0);
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
ThreadPool*
|
||||
get_default_threadpool()
|
||||
{
|
||||
if(TaskRunManager::GetMasterRunManager())
|
||||
return TaskRunManager::GetMasterRunManager()->GetThreadPool();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TaskAllocatorBase::~TaskAllocatorBase() {}
|
||||
intmax_t
|
||||
get_task_depth()
|
||||
{
|
||||
return (ThreadData::GetInstance()) ? ThreadData::GetInstance()->task_depth : 0;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace PTL
|
||||
|
||||
//======================================================================================//
|
||||
+5
-13
@@ -63,20 +63,15 @@ TaskRunManager::GetInstance(bool useTBB)
|
||||
//======================================================================================//
|
||||
|
||||
TaskRunManager::TaskRunManager(bool useTBB)
|
||||
: m_is_initialized(false)
|
||||
, m_verbose(0)
|
||||
, m_workers(std::thread::hardware_concurrency())
|
||||
, m_task_queue(nullptr)
|
||||
, m_thread_pool(nullptr)
|
||||
, m_task_manager(nullptr)
|
||||
: m_workers(std::thread::hardware_concurrency())
|
||||
{
|
||||
if(!GetPrivateMasterRunManager(false))
|
||||
{
|
||||
GetPrivateMasterRunManager(false) = this;
|
||||
}
|
||||
|
||||
#ifdef PTL_USE_TBB
|
||||
auto _useTBB = GetEnv<bool>("FORCE_TBB", useTBB);
|
||||
#if defined(PTL_USE_TBB)
|
||||
auto _useTBB = GetEnv<bool>("PTL_FORCE_TBB", GetEnv<bool>("FORCE_TBB", useTBB));
|
||||
if(_useTBB)
|
||||
useTBB = true;
|
||||
#endif
|
||||
@@ -88,10 +83,6 @@ TaskRunManager::TaskRunManager(bool useTBB)
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
TaskRunManager::~TaskRunManager() {}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
TaskRunManager::Initialize(uint64_t n)
|
||||
{
|
||||
@@ -142,7 +133,8 @@ void
|
||||
TaskRunManager::Terminate()
|
||||
{
|
||||
m_is_initialized = false;
|
||||
m_thread_pool->destroy_threadpool();
|
||||
if(m_thread_pool)
|
||||
m_thread_pool->destroy_threadpool();
|
||||
delete m_task_manager;
|
||||
delete m_thread_pool;
|
||||
m_task_manager = nullptr;
|
||||
|
||||
+4
-8
@@ -41,11 +41,9 @@ ThreadData::GetInstance()
|
||||
//======================================================================================//
|
||||
|
||||
ThreadData::ThreadData(ThreadPool* tp)
|
||||
: is_master(tp->is_master())
|
||||
, within_task(false)
|
||||
, task_depth(0)
|
||||
: is_main((tp) ? tp->is_main() : false)
|
||||
, thread_pool(tp)
|
||||
, current_queue(tp->get_queue())
|
||||
, current_queue((tp) ? tp->get_queue() : nullptr)
|
||||
, queue_stack({ current_queue })
|
||||
{}
|
||||
|
||||
@@ -54,12 +52,10 @@ ThreadData::ThreadData(ThreadPool* tp)
|
||||
void
|
||||
ThreadData::update()
|
||||
{
|
||||
if(!thread_pool)
|
||||
return;
|
||||
current_queue = thread_pool->get_queue();
|
||||
queue_stack.push_back(current_queue);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadData::~ThreadData() {}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
+71
-49
@@ -69,8 +69,9 @@ bool ThreadPool::f_use_tbb = false;
|
||||
// static member function that calls the member function we want the thread to
|
||||
// run
|
||||
void
|
||||
ThreadPool::start_thread(ThreadPool* tp, intmax_t _idx)
|
||||
ThreadPool::start_thread(ThreadPool* tp, thread_data_t* _data, intmax_t _idx)
|
||||
{
|
||||
auto _thr_data = std::make_shared<ThreadData>(tp);
|
||||
{
|
||||
AutoLock lock(TypeMutex<ThreadPool>(), std::defer_lock);
|
||||
if(!lock.owns_lock())
|
||||
@@ -78,9 +79,10 @@ ThreadPool::start_thread(ThreadPool* tp, intmax_t _idx)
|
||||
if(_idx < 0)
|
||||
_idx = f_thread_ids.size();
|
||||
f_thread_ids[std::this_thread::get_id()] = _idx;
|
||||
Threading::SetThreadId(_idx);
|
||||
_data->emplace_back(_thr_data);
|
||||
}
|
||||
static thread_local std::unique_ptr<ThreadData> _unique_data(new ThreadData(tp));
|
||||
thread_data() = _unique_data.get();
|
||||
thread_data() = _thr_data.get();
|
||||
tp->record_entry();
|
||||
tp->execute_thread(thread_data()->current_queue);
|
||||
tp->record_exit();
|
||||
@@ -91,7 +93,7 @@ ThreadPool::start_thread(ThreadPool* tp, intmax_t _idx)
|
||||
bool
|
||||
ThreadPool::using_tbb()
|
||||
{
|
||||
return f_use_tbb;
|
||||
return f_use_tbb;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -111,7 +113,7 @@ ThreadPool::set_use_tbb(bool enable)
|
||||
const ThreadPool::thread_id_map_t&
|
||||
ThreadPool::get_thread_ids()
|
||||
{
|
||||
return f_thread_ids;
|
||||
return f_thread_ids;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
@@ -136,24 +138,12 @@ ThreadPool::get_this_thread_id()
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::ThreadPool(const size_type& pool_size, VUserTaskQueue* task_queue,
|
||||
bool _use_affinity, const affinity_func_t& _affinity_func)
|
||||
bool _use_affinity, affinity_func_t _affinity_func)
|
||||
: m_use_affinity(_use_affinity)
|
||||
, m_tbb_tp(false)
|
||||
, m_verbose(0)
|
||||
, m_pool_size(0)
|
||||
, m_master_tid(ThisThread::get_id())
|
||||
, m_alive_flag(std::make_shared<std::atomic_bool>(false))
|
||||
, m_pool_state(std::make_shared<std::atomic_short>(thread_pool::state::NONINIT))
|
||||
, m_thread_awake(std::make_shared<std::atomic_uintmax_t>(0))
|
||||
, m_task_lock(std::make_shared<Mutex>())
|
||||
, m_task_cond(std::make_shared<Condition>())
|
||||
, m_task_queue(task_queue)
|
||||
, m_tbb_task_group(nullptr)
|
||||
, m_init_func([]() { return; })
|
||||
, m_affinity_func(_affinity_func)
|
||||
, m_affinity_func(std::move(_affinity_func))
|
||||
{
|
||||
m_verbose = GetEnv<int>("PTL_VERBOSE", m_verbose);
|
||||
|
||||
auto master_id = get_this_thread_id();
|
||||
if(master_id != 0 && m_verbose > 1)
|
||||
std::cerr << "ThreadPool created on non-master slave" << std::endl;
|
||||
@@ -179,7 +169,7 @@ ThreadPool::~ThreadPool()
|
||||
<< std::endl;
|
||||
m_pool_state->store(thread_pool::state::STOPPED);
|
||||
m_task_lock->lock();
|
||||
CONDITIONBROADCAST(m_task_cond.get());
|
||||
m_task_cond->notify_all();
|
||||
m_task_lock->unlock();
|
||||
for(auto& itr : m_threads)
|
||||
itr.join();
|
||||
@@ -232,10 +222,10 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
if(!m_alive_flag->load())
|
||||
m_pool_state->store(thread_pool::state::STARTED);
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
// handle tbb task scheduler
|
||||
#ifdef PTL_USE_TBB
|
||||
if(f_use_tbb)
|
||||
#if defined(PTL_USE_TBB)
|
||||
//--------------------------------------------------------------------//
|
||||
// handle tbb task scheduler
|
||||
if(f_use_tbb || m_tbb_tp)
|
||||
{
|
||||
m_tbb_tp = true;
|
||||
m_pool_size = proposed_size;
|
||||
@@ -281,7 +271,10 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
<< std::endl;
|
||||
}
|
||||
if(!m_task_queue)
|
||||
m_task_queue = new UserTaskQueue(m_pool_size);
|
||||
{
|
||||
m_delete_task_queue = true;
|
||||
m_task_queue = new UserTaskQueue(m_pool_size);
|
||||
}
|
||||
return m_pool_size;
|
||||
}
|
||||
else if(m_pool_size == proposed_size) // NOLINT
|
||||
@@ -292,7 +285,10 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
<< std::endl;
|
||||
}
|
||||
if(!m_task_queue)
|
||||
m_task_queue = new UserTaskQueue(m_pool_size);
|
||||
{
|
||||
m_delete_task_queue = true;
|
||||
m_task_queue = new UserTaskQueue(m_pool_size);
|
||||
}
|
||||
return m_pool_size;
|
||||
}
|
||||
}
|
||||
@@ -304,13 +300,18 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
m_is_joined.reserve(proposed_size);
|
||||
}
|
||||
|
||||
if(!m_task_queue)
|
||||
m_task_queue = new UserTaskQueue(proposed_size);
|
||||
|
||||
auto this_tid = get_this_thread_id();
|
||||
for(size_type i = m_pool_size; i < proposed_size; ++i)
|
||||
{
|
||||
// add the threads
|
||||
try
|
||||
{
|
||||
Thread thr(ThreadPool::start_thread, this, this_tid + i + 1);
|
||||
// create thread
|
||||
Thread thr{ ThreadPool::start_thread, this, &m_thread_data,
|
||||
this_tid + i + 1 };
|
||||
// only reaches here if successful creation of thread
|
||||
++m_pool_size;
|
||||
// store thread
|
||||
@@ -354,9 +355,6 @@ ThreadPool::initialize_threadpool(size_type proposed_size)
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if(!m_task_queue)
|
||||
m_task_queue = new UserTaskQueue(m_main_threads.size());
|
||||
|
||||
return m_main_threads.size();
|
||||
}
|
||||
|
||||
@@ -374,13 +372,22 @@ ThreadPool::destroy_threadpool()
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
// handle tbb task scheduler
|
||||
#ifdef PTL_USE_TBB
|
||||
#if defined(PTL_USE_TBB)
|
||||
if(m_tbb_task_group)
|
||||
{
|
||||
m_tbb_task_group->wait();
|
||||
auto _func = [&]() { m_tbb_task_group->wait(); };
|
||||
if(m_tbb_task_arena)
|
||||
m_tbb_task_arena->execute(_func);
|
||||
else
|
||||
_func();
|
||||
delete m_tbb_task_group;
|
||||
m_tbb_task_group = nullptr;
|
||||
}
|
||||
if(m_tbb_task_arena)
|
||||
{
|
||||
delete m_tbb_task_arena;
|
||||
m_tbb_task_arena = nullptr;
|
||||
}
|
||||
if(m_tbb_tp && tbb_global_control())
|
||||
{
|
||||
tbb_global_control_t*& _global_control = tbb_global_control();
|
||||
@@ -397,7 +404,7 @@ ThreadPool::destroy_threadpool()
|
||||
//------------------------------------------------------------------------//
|
||||
// notify all threads we are shutting down
|
||||
m_task_lock->lock();
|
||||
CONDITIONBROADCAST(m_task_cond.get());
|
||||
m_task_cond->notify_all();
|
||||
m_task_lock->unlock();
|
||||
//------------------------------------------------------------------------//
|
||||
|
||||
@@ -440,13 +447,9 @@ ThreadPool::destroy_threadpool()
|
||||
//--------------------------------------------------------------------//
|
||||
// it's joined
|
||||
m_is_joined.at(i) = true;
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
// try waking up a bunch of threads that are still waiting
|
||||
CONDITIONBROADCAST(m_task_cond.get());
|
||||
//--------------------------------------------------------------------//
|
||||
}
|
||||
|
||||
m_thread_data.clear();
|
||||
m_threads.clear();
|
||||
m_main_threads.clear();
|
||||
m_is_joined.clear();
|
||||
@@ -463,12 +466,25 @@ ThreadPool::destroy_threadpool()
|
||||
|
||||
auto _active = m_thread_active->load();
|
||||
|
||||
if(_active == 0)
|
||||
std::cout << "ThreadPool destroyed" << std::endl;
|
||||
else
|
||||
std::cout << "ThreadPool destroyed but " << _active
|
||||
<< " threads might still be active (and cause a termination error)"
|
||||
<< std::endl;
|
||||
if(get_verbose() >= 0)
|
||||
{
|
||||
if(_active == 0)
|
||||
{
|
||||
std::cout << "ThreadPool destroyed" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ThreadPool destroyed but " << _active
|
||||
<< " threads might still be active (and cause a termination error)"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_delete_task_queue)
|
||||
{
|
||||
delete m_task_queue;
|
||||
m_task_queue = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -485,7 +501,7 @@ ThreadPool::stop_thread()
|
||||
// notify all threads we are shutting down
|
||||
m_task_lock->lock();
|
||||
m_is_stopped.push_back(true);
|
||||
CONDITIONNOTIFY(m_task_cond.get());
|
||||
m_task_cond->notify_one();
|
||||
m_task_lock->unlock();
|
||||
//------------------------------------------------------------------------//
|
||||
|
||||
@@ -516,6 +532,16 @@ ThreadPool::stop_thread()
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool::task_queue_t*&
|
||||
ThreadPool::get_valid_queue(task_queue_t*& _queue) const
|
||||
{
|
||||
if(!_queue)
|
||||
_queue = new UserTaskQueue{ static_cast<intmax_t>(m_pool_size) };
|
||||
return _queue;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
|
||||
{
|
||||
@@ -559,8 +585,6 @@ ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
|
||||
if(_task)
|
||||
{
|
||||
(*_task)();
|
||||
if(!_task->group())
|
||||
delete _task;
|
||||
}
|
||||
data->within_task = false;
|
||||
}
|
||||
@@ -674,8 +698,6 @@ ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
|
||||
if(_task)
|
||||
{
|
||||
(*_task)();
|
||||
if(!_task->group())
|
||||
delete _task;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------//
|
||||
|
||||
+1
-32
@@ -21,9 +21,6 @@
|
||||
//
|
||||
// Threading.cc
|
||||
//
|
||||
// ---------------------------------------------------------------
|
||||
// Author: Andrea Dotti (15 Feb 2013): First Implementation
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
#include "PTL/Threading.hh"
|
||||
#include "PTL/AutoLock.hh"
|
||||
@@ -46,7 +43,6 @@ using namespace PTL;
|
||||
namespace
|
||||
{
|
||||
thread_local int ThreadID = Threading::MASTER_ID;
|
||||
std::atomic_int numActThreads(0);
|
||||
} // namespace
|
||||
|
||||
//======================================================================================//
|
||||
@@ -73,21 +69,12 @@ Threading::SetThreadId(int value)
|
||||
{
|
||||
ThreadID = value;
|
||||
}
|
||||
|
||||
int
|
||||
Threading::GetThreadId()
|
||||
{
|
||||
return ThreadID;
|
||||
}
|
||||
bool
|
||||
Threading::IsWorkerThread()
|
||||
{
|
||||
return (ThreadID >= 0);
|
||||
}
|
||||
bool
|
||||
Threading::IsMasterThread()
|
||||
{
|
||||
return (ThreadID == MASTER_ID);
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
@@ -107,21 +94,3 @@ Threading::SetPinAffinity(int cpu, NativeThread& aT)
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
int
|
||||
Threading::WorkerThreadLeavesPool()
|
||||
{
|
||||
return numActThreads--;
|
||||
}
|
||||
int
|
||||
Threading::WorkerThreadJoinsPool()
|
||||
{
|
||||
return numActThreads++;
|
||||
}
|
||||
int
|
||||
Threading::GetNumberOfRunningWorkerThreads()
|
||||
{
|
||||
return numActThreads.load();
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
+32
-47
@@ -47,13 +47,13 @@ UserTaskQueue::UserTaskQueue(intmax_t nworkers, UserTaskQueue* parent)
|
||||
if(!parent)
|
||||
{
|
||||
for(intmax_t i = 0; i < nworkers + 1; ++i)
|
||||
m_subqueues->push_back(new TaskSubQueue(m_ntasks));
|
||||
m_subqueues->emplace_back(new TaskSubQueue(m_ntasks));
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
if(GetEnv<int>("PTL_VERBOSE", 0) > 3)
|
||||
{
|
||||
RecursiveAutoLock l(TypeRecursiveMutex<decltype(std::cout)>());
|
||||
RecursiveAutoLock l(TypeMutex<decltype(std::cout), RecursiveMutex>());
|
||||
std::stringstream ss;
|
||||
ss << ThreadPool::get_this_thread_id() << "> " << ThisThread::get_id() << " ["
|
||||
<< __FUNCTION__ << ":" << __LINE__ << "] "
|
||||
@@ -79,7 +79,7 @@ UserTaskQueue::~UserTaskQueue()
|
||||
{
|
||||
for(auto& itr : *m_subqueues)
|
||||
{
|
||||
assert(itr->size() == 0);
|
||||
assert(itr->empty());
|
||||
delete itr;
|
||||
}
|
||||
m_subqueues->clear();
|
||||
@@ -99,7 +99,7 @@ UserTaskQueue::resize(intmax_t n)
|
||||
{
|
||||
while(m_workers < n)
|
||||
{
|
||||
m_subqueues->push_back(new TaskSubQueue(m_ntasks));
|
||||
m_subqueues->emplace_back(new TaskSubQueue(m_ntasks));
|
||||
++m_workers;
|
||||
}
|
||||
}
|
||||
@@ -235,9 +235,9 @@ UserTaskQueue::GetTask(intmax_t subq, intmax_t nitr)
|
||||
//======================================================================================//
|
||||
|
||||
intmax_t
|
||||
UserTaskQueue::InsertTask(task_pointer task, ThreadData* data, intmax_t subq)
|
||||
UserTaskQueue::InsertTask(task_pointer&& task, ThreadData* data, intmax_t subq)
|
||||
{
|
||||
// skip increment here (handled externally)
|
||||
// increment number of tasks
|
||||
++(*m_ntasks);
|
||||
|
||||
bool spin = m_hold->load(std::memory_order_relaxed);
|
||||
@@ -267,7 +267,7 @@ UserTaskQueue::InsertTask(task_pointer task, ThreadData* data, intmax_t subq)
|
||||
if(task_subq->AcquireClaim())
|
||||
{
|
||||
// push the task into the bin
|
||||
task_subq->PushTask(task);
|
||||
task_subq->PushTask(std::move(task));
|
||||
// release the claim on the bin
|
||||
task_subq->ReleaseClaim();
|
||||
// return success
|
||||
@@ -304,8 +304,8 @@ UserTaskQueue::InsertTask(task_pointer task, ThreadData* data, intmax_t subq)
|
||||
void
|
||||
UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
|
||||
{
|
||||
typedef TaskGroup<int, int> task_group_type;
|
||||
typedef std::map<int64_t, bool> thread_execute_map_t;
|
||||
using task_group_type = TaskGroup<int, int>;
|
||||
using thread_execute_map_t = std::map<int64_t, bool>;
|
||||
|
||||
if(!tp->is_alive())
|
||||
{
|
||||
@@ -313,18 +313,16 @@ UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
|
||||
return;
|
||||
}
|
||||
|
||||
auto join_func = [=](int& ref, int i) {
|
||||
ref += i;
|
||||
return ref;
|
||||
};
|
||||
task_group_type* tg = new task_group_type(join_func, tp);
|
||||
task_group_type tg{ [](int& ref, int i) { return (ref += i); }, tp };
|
||||
|
||||
// wait for all threads to finish any work
|
||||
// NOTE: will cause deadlock if called from a task
|
||||
while(tp->get_active_threads_count() > 0)
|
||||
ThisThread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
thread_execute_map_t* thread_execute_map = new thread_execute_map_t();
|
||||
thread_execute_map_t thread_execute_map{};
|
||||
std::vector<std::shared_ptr<VTask>> _tasks{};
|
||||
_tasks.reserve(m_workers + 1);
|
||||
|
||||
AcquireHold();
|
||||
for(int i = 0; i < (m_workers + 1); ++i)
|
||||
@@ -334,9 +332,10 @@ UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
|
||||
|
||||
//--------------------------------------------------------------------//
|
||||
auto thread_specific_func = [&]() {
|
||||
static Mutex _mtx;
|
||||
ScopeDestructor _dtor = tg.get_scope_destructor();
|
||||
static Mutex _mtx;
|
||||
_mtx.lock();
|
||||
bool& _executed = (*thread_execute_map)[GetThreadBin()];
|
||||
bool& _executed = thread_execute_map[GetThreadBin()];
|
||||
_mtx.unlock();
|
||||
if(!_executed)
|
||||
{
|
||||
@@ -348,25 +347,18 @@ UserTaskQueue::ExecuteOnAllThreads(ThreadPool* tp, function_type func)
|
||||
};
|
||||
//--------------------------------------------------------------------//
|
||||
|
||||
auto _task = tg->wrap(thread_specific_func);
|
||||
//++(*m_ntasks);
|
||||
// TaskSubQueue* task_subq = (*m_subqueues)[i];
|
||||
// task_subq->PushTask(_task);
|
||||
InsertTask(_task, ThreadData::GetInstance(), i);
|
||||
InsertTask(tg.wrap(thread_specific_func), ThreadData::GetInstance(), i);
|
||||
}
|
||||
|
||||
tp->notify_all();
|
||||
int nexecuted = tg->join();
|
||||
int nexecuted = tg.join();
|
||||
if(nexecuted != m_workers)
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Failure executing routine on all threads! Only " << nexecuted
|
||||
<< " threads executed function out of " << m_workers;
|
||||
<< " threads executed function out of " << m_workers << " workers";
|
||||
std::cerr << msg.str() << std::endl;
|
||||
// Exception("UserTaskQueue::ExecuteOnAllThreads", "TaskQueue0000",
|
||||
// JustWarning, msg);
|
||||
}
|
||||
delete thread_execute_map;
|
||||
ReleaseHold();
|
||||
}
|
||||
|
||||
@@ -376,14 +368,10 @@ void
|
||||
UserTaskQueue::ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp,
|
||||
function_type func)
|
||||
{
|
||||
typedef TaskGroup<int, int> task_group_type;
|
||||
typedef std::map<int64_t, bool> thread_execute_map_t;
|
||||
using task_group_type = TaskGroup<int, int>;
|
||||
using thread_execute_map_t = std::map<int64_t, bool>;
|
||||
|
||||
auto join_func = [=](int& ref, int i) {
|
||||
ref += i;
|
||||
return ref;
|
||||
};
|
||||
task_group_type* tg = new task_group_type(join_func, tp);
|
||||
task_group_type tg{ [](int& ref, int i) { return (ref += i); }, tp };
|
||||
|
||||
// wait for all threads to finish any work
|
||||
// NOTE: will cause deadlock if called from a task
|
||||
@@ -396,15 +384,16 @@ UserTaskQueue::ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp,
|
||||
return;
|
||||
}
|
||||
|
||||
thread_execute_map_t* thread_execute_map = new thread_execute_map_t();
|
||||
thread_execute_map_t thread_execute_map{};
|
||||
|
||||
//========================================================================//
|
||||
// wrap the function so that it will only be executed if the thread
|
||||
// has an ID in the set
|
||||
auto thread_specific_func = [=]() {
|
||||
static Mutex _mtx;
|
||||
auto thread_specific_func = [&]() {
|
||||
ScopeDestructor _dtor = tg.get_scope_destructor();
|
||||
static Mutex _mtx;
|
||||
_mtx.lock();
|
||||
bool& _executed = (*thread_execute_map)[GetThreadBin()];
|
||||
bool& _executed = thread_execute_map[GetThreadBin()];
|
||||
_mtx.unlock();
|
||||
if(!_executed && tid_set.count(ThisThread::get_id()) > 0)
|
||||
{
|
||||
@@ -425,21 +414,17 @@ UserTaskQueue::ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp,
|
||||
if(i == GetThreadBin())
|
||||
continue;
|
||||
|
||||
auto _task = tg->wrap(thread_specific_func);
|
||||
InsertTask(_task, ThreadData::GetInstance(), i);
|
||||
InsertTask(tg.wrap(thread_specific_func), ThreadData::GetInstance(), i);
|
||||
}
|
||||
tp->notify_all();
|
||||
int nexecuted = tg->join();
|
||||
if(nexecuted != m_workers)
|
||||
decltype(tid_set.size()) nexecuted = tg.join();
|
||||
if(nexecuted != tid_set.size())
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "Failure executing routine on all threads! Only " << nexecuted
|
||||
<< " threads executed function out of " << tid_set.size();
|
||||
msg << "Failure executing routine on specific threads! Only " << nexecuted
|
||||
<< " threads executed function out of " << tid_set.size() << " workers";
|
||||
std::cerr << msg.str() << std::endl;
|
||||
// Exception("UserTaskQueue::ExecuteOnSpecificThreads", "TaskQueue0001",
|
||||
// JustWarning, msg);
|
||||
}
|
||||
delete thread_execute_map;
|
||||
ReleaseHold();
|
||||
}
|
||||
|
||||
|
||||
Vendored
+5
-67
@@ -31,78 +31,16 @@
|
||||
#include "PTL/VTask.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "PTL/VTaskGroup.hh"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace PTL;
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
VTask::VTask()
|
||||
: m_depth(0)
|
||||
, m_group(nullptr)
|
||||
, m_pool(nullptr)
|
||||
VTask::VTask(bool _is_native, intmax_t _depth)
|
||||
: m_is_native{ _is_native }
|
||||
, m_depth{ _depth }
|
||||
{}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
VTask::VTask(VTaskGroup* task_group)
|
||||
: m_depth(0)
|
||||
, m_group(task_group)
|
||||
, m_pool((m_group) ? task_group->pool() : nullptr)
|
||||
{}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
VTask::VTask(ThreadPool* tp)
|
||||
: m_depth(0)
|
||||
, m_group(nullptr)
|
||||
, m_pool(tp)
|
||||
{}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
VTask::~VTask() {}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
VTask::operator--()
|
||||
{
|
||||
if(m_group)
|
||||
{
|
||||
intmax_t _count = --(*m_group);
|
||||
if(_count < 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_group->task_cond()->notify_all();
|
||||
} catch(std::system_error& e)
|
||||
{
|
||||
auto tid = ThreadPool::get_this_thread_id();
|
||||
AutoLock l(TypeMutex<decltype(std::cerr)>(), std::defer_lock);
|
||||
if(!l.owns_lock())
|
||||
l.lock();
|
||||
std::cerr << "[" << tid << "] Caught system error: " << e.what()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
bool
|
||||
VTask::is_native_task() const
|
||||
{
|
||||
return (m_group) ? m_group->is_native_task_group() : false;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
ThreadPool*
|
||||
VTask::pool() const
|
||||
{
|
||||
return (!m_pool && m_group) ? m_group->pool() : m_pool;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
-220
@@ -1,220 +0,0 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2020 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// ---------------------------------------------------------------
|
||||
// Tasking class implementation
|
||||
//
|
||||
// Class Description:
|
||||
//
|
||||
// This file creates an abstract base class for the grouping the thread-pool
|
||||
// tasking system into independently joinable units
|
||||
//
|
||||
// ---------------------------------------------------------------
|
||||
// Author: Jonathan Madsen (Feb 13th 2018)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
#include "PTL/VTaskGroup.hh"
|
||||
#include "PTL/Globals.hh"
|
||||
#include "PTL/Task.hh"
|
||||
#include "PTL/TaskRunManager.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "PTL/VTask.hh"
|
||||
|
||||
using namespace PTL;
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
std::atomic_uintmax_t&
|
||||
vtask_group_counter()
|
||||
{
|
||||
static std::atomic_uintmax_t _instance(0);
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
int VTaskGroup::f_verbose = GetEnv<int>("PTL_VERBOSE", 0);
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
VTaskGroup::VTaskGroup(ThreadPool* tp)
|
||||
: m_id(vtask_group_counter()++)
|
||||
, m_pool(tp)
|
||||
, m_tot_task_count(std::make_shared<atomic_int>(0))
|
||||
, m_task_cond(std::make_shared<condition_t>())
|
||||
, m_task_lock(std::make_shared<lock_t>())
|
||||
, m_main_tid(std::this_thread::get_id())
|
||||
{
|
||||
if(!m_pool && TaskRunManager::GetMasterRunManager())
|
||||
m_pool = TaskRunManager::GetMasterRunManager()->GetThreadPool();
|
||||
|
||||
if(!m_pool)
|
||||
{
|
||||
std::cerr << __FUNCTION__ << "@" << __LINE__ << " :: Warning! "
|
||||
<< "nullptr to thread pool!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
VTaskGroup::~VTaskGroup() {}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
void
|
||||
VTaskGroup::wait()
|
||||
{
|
||||
// if no pool was initially present at creation
|
||||
if(!m_pool)
|
||||
{
|
||||
// check for master MT run-manager
|
||||
if(TaskRunManager::GetMasterRunManager())
|
||||
m_pool = TaskRunManager::GetMasterRunManager()->GetThreadPool();
|
||||
|
||||
// if MTRunManager does not exist or no thread pool created
|
||||
if(!m_pool)
|
||||
{
|
||||
if(f_verbose > 0)
|
||||
{
|
||||
fprintf(stderr, "%s @ %i :: Warning! nullptr to thread-pool (%p)\n",
|
||||
__FUNCTION__, __LINE__, static_cast<void*>(m_pool));
|
||||
std::cerr << __FUNCTION__ << "@" << __LINE__ << " :: Warning! "
|
||||
<< "nullptr to thread pool!" << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadData* data = ThreadData::GetInstance();
|
||||
if(!data)
|
||||
return;
|
||||
|
||||
ThreadPool* tpool = (m_pool) ? m_pool : data->thread_pool;
|
||||
VUserTaskQueue* taskq = (tpool) ? tpool->get_queue() : data->current_queue;
|
||||
|
||||
bool _is_master = data->is_master;
|
||||
bool _within_task = data->within_task;
|
||||
|
||||
auto is_active_state = [&]() {
|
||||
return (tpool->state()->load(std::memory_order_relaxed) !=
|
||||
thread_pool::state::STOPPED);
|
||||
};
|
||||
|
||||
auto execute_this_threads_tasks = [&]() {
|
||||
if(!taskq)
|
||||
return;
|
||||
|
||||
// only want to process if within a task
|
||||
if((!_is_master || tpool->size() < 2) && _within_task)
|
||||
{
|
||||
int bin = static_cast<int>(taskq->GetThreadBin());
|
||||
// const auto nitr = (tpool) ? tpool->size() : Thread::hardware_concurrency();
|
||||
while(this->pending() > 0)
|
||||
{
|
||||
task_pointer _task = taskq->GetTask(bin);
|
||||
if(_task)
|
||||
(*_task)();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// checks for validity
|
||||
if(!is_native_task_group())
|
||||
{
|
||||
// for external threads
|
||||
if(!_is_master || tpool->size() < 2)
|
||||
return;
|
||||
}
|
||||
else if(f_verbose > 0)
|
||||
{
|
||||
if(!tpool || !taskq)
|
||||
{
|
||||
// something is wrong, didn't create thread-pool?
|
||||
fprintf(
|
||||
stderr,
|
||||
"%s @ %i :: Warning! nullptr to thread data (%p) or task-queue (%p)\n",
|
||||
__FUNCTION__, __LINE__, static_cast<void*>(tpool),
|
||||
static_cast<void*>(taskq));
|
||||
}
|
||||
// return if thread pool isn't built
|
||||
else if(is_native_task_group() && !tpool->is_alive())
|
||||
{
|
||||
fprintf(stderr, "%s @ %i :: Warning! thread-pool is not alive!\n",
|
||||
__FUNCTION__, __LINE__);
|
||||
}
|
||||
else if(!is_active_state())
|
||||
{
|
||||
fprintf(stderr, "%s @ %i :: Warning! thread-pool is not active!\n",
|
||||
__FUNCTION__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
intmax_t wake_size = 2;
|
||||
AutoLock _lock(*m_task_lock, std::defer_lock);
|
||||
|
||||
while(is_active_state())
|
||||
{
|
||||
execute_this_threads_tasks();
|
||||
|
||||
// while loop protects against spurious wake-ups
|
||||
while(_is_master && pending() > 0 && is_active_state())
|
||||
{
|
||||
// auto _wake = [&]() { return (wake_size > pending() || !is_active_state());
|
||||
// };
|
||||
|
||||
// lock before sleeping on condition
|
||||
if(!_lock.owns_lock())
|
||||
_lock.lock();
|
||||
|
||||
// Wait until signaled that a task has been competed
|
||||
// Unlock mutex while wait, then lock it back when signaled
|
||||
// when true, this wakes the thread
|
||||
if(pending() >= wake_size)
|
||||
{
|
||||
m_task_cond->wait(_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_task_cond->wait_for(_lock, std::chrono::microseconds(100));
|
||||
}
|
||||
// unlock
|
||||
if(_lock.owns_lock())
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
// if pending is not greater than zero, we are joined
|
||||
if(pending() <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(_lock.owns_lock())
|
||||
_lock.unlock();
|
||||
|
||||
intmax_t ntask = this->task_count().load();
|
||||
if(ntask > 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "\nWarning! Join operation issue! " << ntask << " tasks still "
|
||||
<< "are running!" << std::endl;
|
||||
std::cerr << ss.str();
|
||||
this->wait();
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
-13
@@ -45,16 +45,3 @@ VUserTaskQueue::VUserTaskQueue(intmax_t nworkers)
|
||||
}
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
VUserTaskQueue::~VUserTaskQueue() {}
|
||||
|
||||
//======================================================================================//
|
||||
/*
|
||||
intmax_t& VUserTaskQueue::ThisThreadNumber() const
|
||||
{
|
||||
// get a thread id number
|
||||
static thread_local intmax_t _tid;
|
||||
return _tid;
|
||||
}
|
||||
*/
|
||||
//======================================================================================//
|
||||
|
||||
Reference in New Issue
Block a user