ATLAS Offline Software
Public Member Functions | Private Member Functions | Private Attributes | List of all members
CaloRecGPU::Helpers::separate_thread_holder< T > Class Template Reference

Manages objects of type T in a thread-safe way, ensuring that there's an object available for each separate thread while minimizing the number of allocations. More...

#include <Helpers.h>

Collaboration diagram for CaloRecGPU::Helpers::separate_thread_holder< T >:

Public Member Functions

T & get_one ()
 
T & get_for_thread () const
 
void release_one ()
 
void resize (const size_t new_size)
 
template<class F , class ... Args>
void operate_on_all (F &&f, Args &&... args)
 
size_t held_size () const
 
size_t available_size () const
 
size_t filled_size () const
 

Private Member Functions

T & add_one_and_return ()
 

Private Attributes

std::vector< std::unique_ptr< T > > m_held
 
std::vector< typename std::thread::idm_thread_equivs
 
std::shared_mutex m_mutex
 

Detailed Description

template<class T>
class CaloRecGPU::Helpers::separate_thread_holder< T >

Manages objects of type T in a thread-safe way, ensuring that there's an object available for each separate thread while minimizing the number of allocations.

Internally uses a std::vector of std::thread::id to manage the different threads, thus it is especially efficient for relatively small numbers of concurrent threads (which matches the use case, e. g. 64 threads )

Definition at line 1479 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

Member Function Documentation

◆ add_one_and_return()

template<class T >
T& CaloRecGPU::Helpers::separate_thread_holder< T >::add_one_and_return ( )
inlineprivate

Definition at line 1497 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1498  {
1499  std::unique_lock<std::shared_mutex> lock(m_mutex);
1500  m_held.emplace_back(std::make_unique<T>());
1501  m_thread_equivs.emplace_back(std::this_thread::get_id());
1502  return *(m_held.back());
1503  }

◆ available_size()

template<class T >
size_t CaloRecGPU::Helpers::separate_thread_holder< T >::available_size ( ) const
inline

Definition at line 1591 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1592  {
1593  std::shared_lock<std::shared_mutex> lock(m_mutex);
1594  size_t count = 0;
1595  const std::thread::id invalid_id{};
1596  for (const auto & id : m_thread_equivs)
1597  {
1598  if (id == invalid_id)
1599  {
1600  ++count;
1601  }
1602  }
1603  return count;
1604  }

◆ filled_size()

template<class T >
size_t CaloRecGPU::Helpers::separate_thread_holder< T >::filled_size ( ) const
inline

Definition at line 1606 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1607  {
1608  std::shared_lock<std::shared_mutex> lock(m_mutex);
1609  size_t count = 0;
1610  const std::thread::id invalid_id{};
1611  for (const auto & id : m_thread_equivs)
1612  {
1613  if (id == invalid_id)
1614  {
1615  ++count;
1616  }
1617  }
1618  return m_held.size() - count;
1619  }

◆ get_for_thread()

template<class T >
T& CaloRecGPU::Helpers::separate_thread_holder< T >::get_for_thread ( ) const
inline
Precondition
Assumes the thread already has an allocated object (through get_one).

Definition at line 1525 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1526  {
1527  std::shared_lock<std::shared_mutex> lock(m_mutex);
1528  std::thread::id this_id = std::this_thread::get_id();
1529  for (size_t i = 0; i < m_thread_equivs.size(); ++i)
1530  {
1531  if (m_thread_equivs[i] == this_id)
1532  {
1533  return *(m_held[i]);
1534  }
1535  }
1536  //Here would be a good place for an unreachable.
1537  //C++23?
1538  return *(m_held.back());
1539  }

◆ get_one()

template<class T >
T& CaloRecGPU::Helpers::separate_thread_holder< T >::get_one ( )
inline

Definition at line 1506 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1507  {
1508  {
1509  std::shared_lock<std::shared_mutex> lock(m_mutex);
1510  std::thread::id this_id = std::this_thread::get_id();
1511  const std::thread::id invalid_id{};
1512  for (size_t i = 0; i < m_thread_equivs.size(); ++i)
1513  {
1514  if (m_thread_equivs[i] == invalid_id)
1515  {
1516  m_thread_equivs[i] = this_id;
1517  return *(m_held[i]);
1518  }
1519  }
1520  }
1521  return add_one_and_return();
1522  }

◆ held_size()

template<class T >
size_t CaloRecGPU::Helpers::separate_thread_holder< T >::held_size ( ) const
inline

Definition at line 1585 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1586  {
1587  std::shared_lock<std::shared_mutex> lock(m_mutex);
1588  return m_held.size();
1589  }

◆ operate_on_all()

template<class T >
template<class F , class ... Args>
void CaloRecGPU::Helpers::separate_thread_holder< T >::operate_on_all ( F &&  f,
Args &&...  args 
)
inline

Definition at line 1576 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1577  {
1578  std::unique_lock<std::shared_mutex> lock(m_mutex);
1579  for (std::unique_ptr<T> & obj : m_held)
1580  {
1581  f(*obj, std::forward<Args>(args)...);
1582  }
1583  }

◆ release_one()

template<class T >
void CaloRecGPU::Helpers::separate_thread_holder< T >::release_one ( )
inline

Definition at line 1541 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1542  {
1543  std::unique_lock<std::shared_mutex> lock(m_mutex);
1544  std::thread::id this_id = std::this_thread::get_id();
1545  const std::thread::id invalid_id{};
1546  for (size_t i = 0; i < m_thread_equivs.size(); ++i)
1547  {
1548  if (m_thread_equivs[i] == this_id)
1549  {
1550  m_thread_equivs[i] = invalid_id;
1551  }
1552  }
1553  }

◆ resize()

template<class T >
void CaloRecGPU::Helpers::separate_thread_holder< T >::resize ( const size_t  new_size)
inline

Definition at line 1555 of file Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h.

1556  {
1557  std::unique_lock<std::shared_mutex> lock(m_mutex);
1558  if (new_size < m_held.size())
1559  {
1560  m_held.resize(new_size);
1561  m_thread_equivs.resize(new_size);
1562  }
1563  else if (new_size > m_held.size())
1564  {
1565  const size_t to_add = new_size - m_held.size();
1566  const std::thread::id invalid_id{};
1567  for (size_t i = 0; i < to_add; ++i)
1568  {
1569  m_held.emplace_back(std::make_unique<T>());
1570  m_thread_equivs.emplace_back(invalid_id);
1571  }
1572  }
1573  }

Member Data Documentation

◆ m_held

template<class T >
std::vector< std::unique_ptr<T> > CaloRecGPU::Helpers::separate_thread_holder< T >::m_held
private

◆ m_mutex

template<class T >
std::shared_mutex CaloRecGPU::Helpers::separate_thread_holder< T >::m_mutex
mutableprivate

◆ m_thread_equivs

template<class T >
std::vector< typename std::thread::id > CaloRecGPU::Helpers::separate_thread_holder< T >::m_thread_equivs
private

The documentation for this class was generated from the following file:
python.CaloAddPedShiftConfig.args
args
Definition: CaloAddPedShiftConfig.py:47
CaloRecGPU::Helpers::separate_thread_holder::add_one_and_return
T & add_one_and_return()
Definition: Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h:1497
CaloRecGPU::Helpers::separate_thread_holder::m_held
std::vector< std::unique_ptr< T > > m_held
Definition: Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h:1482
python.RatesEmulationExample.lock
lock
Definition: RatesEmulationExample.py:148
XMLtoHeader.count
count
Definition: XMLtoHeader.py:84
CaloRecGPU::Helpers::separate_thread_holder::m_mutex
std::shared_mutex m_mutex
Definition: Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h:1495
lumiFormat.i
int i
Definition: lumiFormat.py:85
CaloRecGPU::Helpers::separate_thread_holder::m_thread_equivs
std::vector< typename std::thread::id > m_thread_equivs
Definition: Calorimeter/CaloRecGPU/CaloRecGPU/Helpers.h:1483
hist_file_dump.f
f
Definition: hist_file_dump.py:140
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:239
python.PyAthena.obj
obj
Definition: PyAthena.py:132