SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
reader_writer_manager.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2021, 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 <functional>
17 #include <mutex>
18 #include <seqan3/std/new>
19 
23 
24 namespace seqan3::detail
25 {
26 
30 struct writer_count : public detail::strong_type<size_t, writer_count>
31 {
33  using base_t = detail::strong_type<size_t, writer_count>;
34 
36  using base_t::base_t;
37 };
38 
42 struct reader_count : public detail::strong_type<size_t, reader_count>
43 {
45  using base_t = detail::strong_type<size_t, reader_count>;
46 
48  using base_t::base_t;
49 };
50 
73 class reader_writer_manager
74 {
75 private:
76 
78  class [[nodiscard]] scoped_writer_type
79  {
80  public:
85  scoped_writer_type() = delete;
86  scoped_writer_type(scoped_writer_type const &) = default;
87  scoped_writer_type(scoped_writer_type &&) = default;
88  scoped_writer_type & operator=(scoped_writer_type const &) = default;
89  scoped_writer_type & operator=(scoped_writer_type &&) = default;
90 
94  explicit scoped_writer_type(reader_writer_manager & _manager) : manager{_manager}
95  {}
96 
98  ~scoped_writer_type()
99  {
100  manager.writer_arrive();
101  }
103 
105  reader_writer_manager & manager;
106  };
107 
109  class [[nodiscard]] scoped_reader_type
110  {
111  public:
115  scoped_reader_type() = delete;
116  scoped_reader_type(scoped_reader_type const &) = default;
117  scoped_reader_type(scoped_reader_type &&) = default;
118  scoped_reader_type & operator=(scoped_reader_type const &) = default;
119  scoped_reader_type & operator=(scoped_reader_type &&) = default;
120 
124  explicit scoped_reader_type(reader_writer_manager & _manager) : manager{_manager}
125  {}
126 
128  ~scoped_reader_type()
129  {
130  manager.reader_arrive();
131  }
133 
135  reader_writer_manager & manager;
136  };
137 
138 public:
142  reader_writer_manager() = delete;
143  reader_writer_manager(reader_writer_manager const &) = delete;
144  reader_writer_manager(reader_writer_manager &&) = delete;
145  reader_writer_manager & operator=(reader_writer_manager const &) = delete;
146  reader_writer_manager & operator=(reader_writer_manager &&) = delete;
147  ~reader_writer_manager() = default;
148 
165  template <typename concurrent_t>
167  requires requires { std::declval<concurrent_t>().close(); } // requires closable concurrent data structure.
169  reader_writer_manager(reader_count const rcount, writer_count const wcount, concurrent_t & ds) :
170  reader_latch{static_cast<ptrdiff_t>(rcount.get())},
171  writer_latch{static_cast<ptrdiff_t>(wcount.get())},
172  completion_fn{[&ds] () { ds.close(); }}
173  {
174  if (rcount.get() < 1 || wcount.get() < 1)
175  throw std::invalid_argument{"Both, reader count and writer count must be at least 1."};
176  }
178 
195  void writer_arrive_and_wait() noexcept
196  {
197  writer_latch.arrive_and_wait();
198 
199  std::call_once(flag, completion_fn);
200  }
201 
218  void writer_arrive() noexcept
219  {
220  writer_latch.arrive();
221 
222  if (writer_latch.try_wait())
223  std::call_once(flag, completion_fn);
224  }
225 
241  void reader_arrive_and_wait() noexcept
242  {
243  reader_latch.arrive_and_wait();
244  }
245 
260  void reader_arrive() noexcept
261  {
262  reader_latch.arrive();
263  }
264 
282  scoped_writer_type register_writer() noexcept
283  {
284  return scoped_writer_type{*this};
285  }
286 
304  scoped_reader_type register_reader() noexcept
305  {
306  return scoped_reader_type{*this};
307  }
308 
309 private:
310 
312  alignas(std::hardware_destructive_interference_size) latch reader_latch;
314  alignas(std::hardware_destructive_interference_size) latch writer_latch;
318  std::function<void()> completion_fn;
319 };
320 
321 } // namespace seqan3::detail
T call_once(T... args)
constexpr std::size_t hardware_destructive_interference_size
Minimum offset between two objects to avoid false sharing.
Definition: new:34
constexpr auto const & get(configuration< configs_t... > const &config) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: configuration.hpp:429
Provides C++17/20 additions to the <new> header, if they are not already available.
Provides basic data structure for strong types.
Provides seqan3::detail::latch.
Provides seqan3::detail::spin_delay.