SeqAn3  3.0.1
The Modern C++ library for sequence analysis.
reader_writer_manager.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
13 #pragma once
14 
15 #include <cassert>
16 #include <mutex>
17 
21 #include <seqan3/std/new>
22 
23 namespace seqan3::detail
24 {
25 
29 struct writer_count : public detail::strong_type<size_t, writer_count>
30 {
32  using base_t = detail::strong_type<size_t, writer_count>;
33 
35  using base_t::base_t;
36 };
37 
41 struct reader_count : public detail::strong_type<size_t, reader_count>
42 {
44  using base_t = detail::strong_type<size_t, reader_count>;
45 
47  using base_t::base_t;
48 };
49 
72 class reader_writer_manager
73 {
74 private:
75 
77  class [[nodiscard]] scoped_writer_type
78  {
79  public:
84  scoped_writer_type() = delete;
85  scoped_writer_type(scoped_writer_type const &) = default;
86  scoped_writer_type(scoped_writer_type &&) = default;
87  scoped_writer_type & operator=(scoped_writer_type const &) = default;
88  scoped_writer_type & operator=(scoped_writer_type &&) = default;
89 
93  explicit scoped_writer_type(reader_writer_manager & _manager) : manager{_manager}
94  {}
95 
97  ~scoped_writer_type()
98  {
99  manager.writer_arrive();
100  }
102 
104  reader_writer_manager & manager;
105  };
106 
108  class [[nodiscard]] scoped_reader_type
109  {
110  public:
114  scoped_reader_type() = delete;
115  scoped_reader_type(scoped_reader_type const &) = default;
116  scoped_reader_type(scoped_reader_type &&) = default;
117  scoped_reader_type & operator=(scoped_reader_type const &) = default;
118  scoped_reader_type & operator=(scoped_reader_type &&) = default;
119 
123  explicit scoped_reader_type(reader_writer_manager & _manager) : manager{_manager}
124  {}
125 
127  ~scoped_reader_type()
128  {
129  manager.reader_arrive();
130  }
132 
134  reader_writer_manager & manager;
135  };
136 
137 public:
141  reader_writer_manager() = delete;
142  reader_writer_manager(reader_writer_manager const &) = delete;
143  reader_writer_manager(reader_writer_manager &&) = delete;
144  reader_writer_manager & operator=(reader_writer_manager const &) = delete;
145  reader_writer_manager & operator=(reader_writer_manager &&) = delete;
146  ~reader_writer_manager() = default;
147 
164  template <typename concurrent_t>
166  requires requires { std::declval<concurrent_t>().close(); } // requires closable concurrent data structure.
168  reader_writer_manager(reader_count const rcount, writer_count const wcount, concurrent_t & ds) :
169  reader_latch{static_cast<ptrdiff_t>(rcount.get())},
170  writer_latch{static_cast<ptrdiff_t>(wcount.get())},
171  completion_fn{[&ds] () { ds.close(); }}
172  {
173  if (rcount.get() < 1 || wcount.get() < 1)
174  throw std::invalid_argument{"Both, reader count and writer count must be at least 1."};
175  }
177 
194  void writer_arrive_and_wait() noexcept
195  {
196  writer_latch.arrive_and_wait();
197 
198  std::call_once(flag, completion_fn);
199  }
200 
217  void writer_arrive() noexcept
218  {
219  writer_latch.arrive();
220 
221  if (writer_latch.try_wait())
222  std::call_once(flag, completion_fn);
223  }
224 
240  void reader_arrive_and_wait() noexcept
241  {
242  reader_latch.arrive_and_wait();
243  }
244 
259  void reader_arrive() noexcept
260  {
261  reader_latch.arrive();
262  }
263 
281  scoped_writer_type register_writer() noexcept
282  {
283  return scoped_writer_type{*this};
284  }
285 
303  scoped_reader_type register_reader() noexcept
304  {
305  return scoped_reader_type{*this};
306  }
307 
308 private:
309 
311  alignas(std::hardware_destructive_interference_size) latch reader_latch;
313  alignas(std::hardware_destructive_interference_size) latch writer_latch;
317  std::function<void()> completion_fn;
318 };
319 
320 } // namespace seqan3::detail
std::call_once
T call_once(T... args)
strong_type.hpp
Provides basic data structure for strong types.
std::hardware_destructive_interference_size
constexpr std::size_t hardware_destructive_interference_size
Minimum offset between two objects to avoid false sharing.
Definition: new:34
std::function
new
Provides C++17/20 additions to the <new> header, if they are not already available.
std::once_flag
latch.hpp
Provides seqan3::detail::latch.
std::invalid_argument
spin_delay.hpp
Provides seqan3::detail::spin_delay.
cassert
mutex
seqan3::field::flag
The alignment flag (bit information), uint16_t value.