GEOSX
FixedSizeDequeWithMutexes.hpp
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2018-2020 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University
7  * Copyright (c) 2018-2020 TotalEnergies
8  * Copyright (c) 2019- GEOSX Contributors
9  * All rights reserved
10  *
11  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
12  * ------------------------------------------------------------------------------------------------------------
13  */
14 #ifndef FIXEDSIZEDEQUEWITHMUTEXES_HPP
15 #define FIXEDSIZEDEQUEWITHMUTEXES_HPP
16 
17 #include <future>
18 #include <mutex>
19 #include <condition_variable>
20 #include <camp/camp.hpp>
21 
22 #include "common/FixedSizeDeque.hpp"
23 #include "common/MultiMutexesLock.hpp"
24 
25 namespace geos
26 {
28 template< typename T, typename INDEX_TYPE >
29 class FixedSizeDequeWithMutexes : public FixedSizeDeque< T, INDEX_TYPE >
30 {
31 public:
33  std::mutex m_frontMutex;
35  std::mutex m_backMutex;
37  std::mutex m_popMutex;
39  std::mutex m_emplaceMutex;
41  std::condition_variable_any m_notFullCond;
43  std::condition_variable_any m_notEmptyCond;
44 
52  FixedSizeDequeWithMutexes( int maxEntries, int valuesPerEntry, LvArray::MemorySpace space ): FixedSizeDeque< T, INDEX_TYPE >( maxEntries, valuesPerEntry, space,
53 #ifdef GEOSX_USE_CUDA
54  camp::resources::Resource{ camp::resources::Cuda{} }
55 #else
56  camp::resources::Resource{ camp::resources::Host{} }
57 #endif
58  ) {}
59 
66  camp::resources::Event emplaceFront( arrayView1d< T > array )
67  {
68  LIFO_MARK_FUNCTION;
69  camp::resources::Event e;
70  {
72  {
73  LIFO_MARK_SCOPE( waitingForBuffer );
74  m_notFullCond.wait( lock, [ this ] { return !this->full(); } );
75  }
76  {
77  LIFO_MARK_SCOPE( copy );
78  e = FixedSizeDeque< T, INDEX_TYPE >::emplace_front( array.toSliceConst() );
79  }
80  }
81  m_notEmptyCond.notify_all();
82  return e;
83  }
84 
91  camp::resources::Event popFront( arrayView1d< T > array )
92  {
93  LIFO_MARK_FUNCTION;
94  camp::resources::Event e;
95  {
96  auto lock = make_multilock( m_popMutex, m_frontMutex );
97  {
98  LIFO_MARK_SCOPE( waitingForBuffer );
99  m_notEmptyCond.wait( lock, [ this ] { return !this->empty(); } );
100  }
101  // deadlock can occur if frontMutex is taken after an
102  // emplaceMutex (inside pushAsync) but this is prevented by the
103  // pushWait() in popAsync.
104  {
105  LIFO_MARK_SCOPE( copy );
106  camp::resources::Resource r = this->getStream();
107  e = LvArray::memcpy( r, array.toSlice(), this->front() );
108  this->pop_front();
109  }
110  }
111  m_notFullCond.notify_all();
112  return e;
113  }
114 
121  {
122  LIFO_MARK_FUNCTION;
123  {
125  while( this->full() || q2.empty() )
126  {
127  {
128  LIFO_MARK_SCOPE( WaitForBufferToEmplace );
129  m_notFullCond.wait( lock, [ this ] { return !this->full(); } );
130  }
131  {
132  LIFO_MARK_SCOPE( WaitForBufferToPop );
133  q2.m_notEmptyCond.wait( lock, [ &q2 ] { return !q2.empty(); } );
134  }
135  }
136  LIFO_MARK_SCOPE( Transfert );
137  this->emplace_front( q2.back() ).wait();
138  q2.pop_back();
139  }
140  q2.m_notFullCond.notify_all();
141  m_notEmptyCond.notify_all();
142  }
143 
150  {
151  LIFO_MARK_FUNCTION;
152  {
154  while( this->full() || q2.empty() )
155  {
156  m_notFullCond.wait( lock, [ this ] { return !this->full(); } );
157  q2.m_notEmptyCond.wait( lock, [ &q2 ] { return !q2.empty(); } );
158  }
159  this->emplace_back( q2.front() ).wait();
160  q2.pop_front();
161  }
162  m_notEmptyCond.notify_all();
163  q2.m_notFullCond.notify_all();
164  }
165 };
166 }
167 #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:220
auto make_multilock(Mutexes &&... mutexes)
Helper to construct MultiMutexesLock (usage auto lock = make_multilock( mutex1, mutex2,...