GEOS
FixedSizeDequeWithMutexes.hpp
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2024 TotalEnergies
7  * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
8  * Copyright (c) 2023-2024 Chevron
9  * Copyright (c) 2019- GEOS/GEOSX Contributors
10  * All rights reserved
11  *
12  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
13  * ------------------------------------------------------------------------------------------------------------
14  */
15 
16 #ifndef FIXEDSIZEDEQUEWITHMUTEXES_HPP
17 #define FIXEDSIZEDEQUEWITHMUTEXES_HPP
18 
19 #include <future>
20 #include <mutex>
21 #include <condition_variable>
22 #include <camp/camp.hpp>
23 
24 #include "common/FixedSizeDeque.hpp"
25 #include "common/MultiMutexesLock.hpp"
26 
27 namespace geos
28 {
30 template< typename T, typename INDEX_TYPE >
31 class FixedSizeDequeWithMutexes : public FixedSizeDeque< T, INDEX_TYPE >
32 {
33 public:
35  std::mutex m_frontMutex;
37  std::mutex m_backMutex;
39  std::mutex m_popMutex;
41  std::mutex m_emplaceMutex;
43  std::condition_variable_any m_notFullCond;
45  std::condition_variable_any m_notEmptyCond;
46 
54  FixedSizeDequeWithMutexes( int maxEntries, int valuesPerEntry, LvArray::MemorySpace space ): FixedSizeDeque< T, INDEX_TYPE >( maxEntries, valuesPerEntry, space,
55 #ifdef GEOS_USE_CUDA
56  camp::resources::Resource{ camp::resources::Cuda{} }
57 #else
58  camp::resources::Resource{ camp::resources::Host{} }
59 #endif
60  ) {}
61 
68  camp::resources::Event emplaceFront( arrayView1d< T > array )
69  {
70  LIFO_MARK_FUNCTION;
71  camp::resources::Event e;
72  {
74  {
75  LIFO_MARK_SCOPE( waitingForBuffer );
76  m_notFullCond.wait( lock, [ this ] { return !this->full(); } );
77  }
78  {
79  LIFO_MARK_SCOPE( copy );
80  e = FixedSizeDeque< T, INDEX_TYPE >::emplace_front( array.toSliceConst() );
81  }
82  }
83  m_notEmptyCond.notify_all();
84  return e;
85  }
86 
93  camp::resources::Event popFront( arrayView1d< T > array )
94  {
95  LIFO_MARK_FUNCTION;
96  camp::resources::Event e;
97  {
98  auto lock = make_multilock( m_popMutex, m_frontMutex );
99  {
100  LIFO_MARK_SCOPE( waitingForBuffer );
101  m_notEmptyCond.wait( lock, [ this ] { return !this->empty(); } );
102  }
103  // deadlock can occur if frontMutex is taken after an
104  // emplaceMutex (inside pushAsync) but this is prevented by the
105  // pushWait() in popAsync.
106  {
107  LIFO_MARK_SCOPE( copy );
108  camp::resources::Resource r = this->getStream();
109  e = LvArray::memcpy( r, array.toSlice(), this->front() );
110  this->pop_front();
111  }
112  }
113  m_notFullCond.notify_all();
114  return e;
115  }
116 
123  {
124  LIFO_MARK_FUNCTION;
125  {
127  while( this->full() || q2.empty() )
128  {
129  {
130  LIFO_MARK_SCOPE( WaitForBufferToEmplace );
131  m_notFullCond.wait( lock, [ this ] { return !this->full(); } );
132  }
133  {
134  LIFO_MARK_SCOPE( WaitForBufferToPop );
135  q2.m_notEmptyCond.wait( lock, [ &q2 ] { return !q2.empty(); } );
136  }
137  }
138  LIFO_MARK_SCOPE( Transfert );
139  this->emplace_front( q2.back() ).wait();
140  q2.pop_back();
141  }
142  q2.m_notFullCond.notify_all();
143  m_notEmptyCond.notify_all();
144  }
145 
152  {
153  LIFO_MARK_FUNCTION;
154  {
156  while( this->full() || q2.empty() )
157  {
158  m_notFullCond.wait( lock, [ this ] { return !this->full(); } );
159  q2.m_notEmptyCond.wait( lock, [ &q2 ] { return !q2.empty(); } );
160  }
161  this->emplace_back( q2.front() ).wait();
162  q2.pop_front();
163  }
164  m_notEmptyCond.notify_all();
165  q2.m_notFullCond.notify_all();
166  }
167 };
168 }
169 #endif // FIXEDSIZEDEQUEWITHMUTEXES_HPP
Implement a double ended queue with fixed number of fixed size buffer to be stored.
camp::resources::Resource getStream()
camp::resources::Event emplace_back(const LvArray::ArraySlice< T const, 1, 0, INDEX_TYPE2 > &src)
ArraySlice1DLarge back() const
camp::resources::Event emplace_front(const LvArray::ArraySlice< T const, 1, 0, INDEX_TYPE2 > &src)
void pop_back()
Removes last array of the queue.
void pop_front()
Removes first array of the queue.
ArraySlice1DLarge front() const
Associate mutexes with the fixedSizeDeque.
std::mutex m_frontMutex
Mutex to protect access to the front.
std::mutex m_emplaceMutex
Mutex to prevent two simulteaneous emplace (can be an issue for last one)
camp::resources::Event emplaceFront(arrayView1d< T > array)
std::condition_variable_any m_notEmptyCond
Condition used to notify when queue is not empty.
std::condition_variable_any m_notFullCond
Condition used to notify when queue is not full.
std::mutex m_popMutex
Mutex to prevent two simulteaneous pop (can be an issue for last one)
camp::resources::Event popFront(arrayView1d< T > array)
std::mutex m_backMutex
Mutex to protect access to the back.
void emplaceFrontFromBack(FixedSizeDequeWithMutexes< T, INDEX_TYPE > &q2)
FixedSizeDequeWithMutexes(int maxEntries, int valuesPerEntry, LvArray::MemorySpace space)
void emplaceBackFromFront(FixedSizeDequeWithMutexes< T, INDEX_TYPE > &q2)
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:188
auto make_multilock(Mutexes &&... mutexes)
Helper to construct MultiMutexesLock (usage auto lock = make_multilock( mutex1, mutex2,...