dune-common  2.8.0
mpifuture.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef DUNE_COMMON_PARALLEL_MPIFUTURE_HH
4 #define DUNE_COMMON_PARALLEL_MPIFUTURE_HH
5 
6 #include <optional>
7 
11 
12 #if HAVE_MPI
13 namespace Dune{
14 
15  namespace impl{
16  template<class T>
17  struct Buffer{
18  Buffer(bool valid){
19  if(valid)
20  value = std::make_unique<T>();
21  }
22  template<class V>
23  Buffer(V&& t)
24  : value(std::make_unique<T>(std::forward<V>(t)))
25  {}
26  std::unique_ptr<T> value;
27  T get(){
28  T tmp = std::move(*value);
29  value.reset();
30  return tmp;
31  }
32  operator bool () const {
33  return (bool)value;
34  }
35  T& operator *() const{
36  return *value;
37  }
38  };
39 
40  template<class T>
41  struct Buffer<T&>{
42  Buffer(bool valid = false)
43  {
44  if(valid)
45  value = T();
46  }
47  template<class V>
48  Buffer(V&& t)
49  : value(std::forward<V>(t))
50  {}
51  std::optional<std::reference_wrapper<T>> value;
52  T& get(){
53  T& tmp = *value;
54  value.reset();
55  return tmp;
56  }
57  operator bool () const{
58  return (bool)value;
59  }
60  T& operator *() const{
61  return *value;
62  }
63  };
64 
65  template<>
66  struct Buffer<void>{
67  bool valid_;
68  Buffer(bool valid = false)
69  : valid_(valid)
70  {}
71  operator bool () const{
72  return valid_;
73  }
74  void get(){}
75  };
76  }
77 
82  template<class R, class S = void>
83  class MPIFuture{
84  mutable MPI_Request req_;
85  mutable MPI_Status status_;
86  impl::Buffer<R> data_;
87  impl::Buffer<S> send_data_;
88  friend class Communication<MPI_Comm>;
89  public:
90  MPIFuture(bool valid = false)
91  : req_(MPI_REQUEST_NULL)
92  , data_(valid)
93  {}
94 
95  // Hide this constructor if R or S is void
96  template<class V = R, class U = S>
97  MPIFuture(V&& recv_data, U&& send_data, typename std::enable_if_t<!std::is_void<V>::value && !std::is_void<U>::value>* = 0) :
98  req_(MPI_REQUEST_NULL)
99  , data_(std::forward<R>(recv_data))
100  , send_data_(std::forward<S>(send_data))
101  {}
102 
103  // hide this constructor if R is void
104  template<class V = R>
105  MPIFuture(V&& recv_data, typename std::enable_if_t<!std::is_void<V>::value>* = 0)
106  : req_(MPI_REQUEST_NULL)
107  , data_(std::forward<V>(recv_data))
108  {}
109 
111  if(req_ != MPI_REQUEST_NULL){
112  try{ // might fail when it is a collective communication
113  MPI_Cancel(&req_);
114  MPI_Request_free(&req_);
115  }catch(...){
116  }
117  }
118  }
119 
121  : req_(MPI_REQUEST_NULL)
122  , data_(std::move(f.data_))
123  , send_data_(std::move(f.send_data_))
124  {
125  std::swap(req_, f.req_);
126  std::swap(status_, f.status_);
127  }
128 
130  std::swap(req_, f.req_);
131  std::swap(status_, f.status_);
132  std::swap(data_, f.data_);
133  std::swap(send_data_, f.send_data_);
134  return *this;
135  }
136 
137  bool valid() const{
138  return (bool)data_;
139  }
140 
141  void wait(){
142  if(!valid())
143  DUNE_THROW(InvalidFutureException, "The MPIFuture is not valid!");
144  MPI_Wait(&req_, &status_);
145  }
146 
147  bool ready() const{
148  int flag = -1;
149  MPI_Test(&req_, &flag, &status_);
150  return flag;
151  }
152 
153  R get() {
154  wait();
155  return data_.get();
156  }
157 
159  wait();
160  return send_data_.get();
161  }
162 
163  auto get_mpidata(){
164  return getMPIData(*data_);
165  }
166 
168  return getMPIData(*send_data_);
169  }
170  };
171 
172 }
173 #endif
174 #endif
Implements an utility class that provides collective communication methods for sequential programs.
Interface class to translate objects to a MPI_Datatype, void* and size used for MPI calls.
bigunsignedint< k > operator*(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:544
#define DUNE_THROW(E, m)
Definition: exceptions.hh:216
Dune namespace.
Definition: alignedallocator.hh:11
auto getMPIData(T &t)
Definition: mpidata.hh:41
void swap(T &v1, T &v2, bool mask)
Definition: simd.hh:470
Collective communication interface and sequential default implementation.
Definition: communication.hh:98
This exception is thrown when ready(), wait() or get() is called on an invalid future....
Definition: future.hh:16
Definition: mpifuture.hh:17
std::unique_ptr< T > value
Definition: mpifuture.hh:26
T & operator*() const
Definition: mpifuture.hh:35
Buffer(V &&t)
Definition: mpifuture.hh:23
T get()
Definition: mpifuture.hh:27
Buffer(bool valid)
Definition: mpifuture.hh:18
T & get()
Definition: mpifuture.hh:52
std::optional< std::reference_wrapper< T > > value
Definition: mpifuture.hh:51
Buffer(bool valid=false)
Definition: mpifuture.hh:42
Buffer(V &&t)
Definition: mpifuture.hh:48
bool valid_
Definition: mpifuture.hh:67
void get()
Definition: mpifuture.hh:74
Buffer(bool valid=false)
Definition: mpifuture.hh:68
Provides a future-like object for MPI communication. It contains the object that will be received and...
Definition: mpifuture.hh:83
MPIFuture(V &&recv_data, typename std::enable_if_t<!std::is_void< V >::value > *=0)
Definition: mpifuture.hh:105
bool ready() const
Definition: mpifuture.hh:147
bool valid() const
Definition: mpifuture.hh:137
~MPIFuture()
Definition: mpifuture.hh:110
MPIFuture(bool valid=false)
Definition: mpifuture.hh:90
auto get_send_mpidata()
Definition: mpifuture.hh:167
MPIFuture & operator=(MPIFuture &&f)
Definition: mpifuture.hh:129
void wait()
Definition: mpifuture.hh:141
auto get_mpidata()
Definition: mpifuture.hh:163
R get()
Definition: mpifuture.hh:153
MPIFuture(V &&recv_data, U &&send_data, typename std::enable_if_t<!std::is_void< V >::value &&!std::is_void< U >::value > *=0)
Definition: mpifuture.hh:97
S get_send_data()
Definition: mpifuture.hh:158
MPIFuture(MPIFuture &&f)
Definition: mpifuture.hh:120