SeqAn3 3.1.0
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
24namespace seqan3::detail
25{
26
30struct 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
42struct 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
72class reader_writer_manager
73{
74private:
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
137public:
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
308private:
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
T call_once(T... args)
constexpr std::size_t hardware_destructive_interference_size
Minimum offset between two objects to avoid false sharing.
Definition: new:32
Provides seqan3::detail::latch.
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
The <new> header from C++17's standard library.
Provides seqan3::detail::spin_delay.
Provides basic data structure for strong types.