2 Copyright (c) 2005-2019 Intel Corporation
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 #include "internal/_deprecated_header_message_guard.h"
19 #if !defined(__TBB_show_deprecation_message_reader_writer_lock_H) && defined(__TBB_show_deprecated_header_message)
20 #define __TBB_show_deprecation_message_reader_writer_lock_H
21 #pragma message("TBB Warning: tbb/reader_writer_lock.h is deprecated. For details, please see Deprecated Features appendix in the TBB reference manual.")
24 #if defined(__TBB_show_deprecated_header_message)
25 #undef __TBB_show_deprecated_header_message
28 #ifndef __TBB_reader_writer_lock_H
29 #define __TBB_reader_writer_lock_H
31 #define __TBB_reader_writer_lock_H_include_area
32 #include "internal/_warning_suppress_enable_notice.h"
34 #include "tbb_thread.h"
35 #include "tbb_allocator.h"
39 namespace interface5 {
40 //! Writer-preference reader-writer lock with local-only spinning on readers.
41 /** Loosely adapted from Mellor-Crummey and Scott pseudocode at
42 http://www.cs.rochester.edu/research/synchronization/pseudocode/rw.html#s_wp
43 @ingroup synchronization */
44 class __TBB_DEPRECATED_VERBOSE_MSG("tbb::reader_writer_lock is deprecated, use std::shared_mutex")
45 reader_writer_lock : tbb::internal::no_copy {
47 friend class scoped_lock;
48 friend class scoped_lock_read;
49 //! Status type for nodes associated with lock instances
50 /** waiting_nonblocking: the wait state for nonblocking lock
51 instances; for writes, these transition straight to active
52 states; for reads, these are unused.
54 waiting: the start and spin state for all lock instances; these will
55 transition to active state when appropriate. Non-blocking write locks
56 transition from this state to waiting_nonblocking immediately.
58 active: the active state means that the lock instance holds
59 the lock; it will transition to invalid state during node deletion
61 invalid: the end state for all nodes; this is set in the
62 destructor so if we encounter this state, we are looking at
63 memory that has already been freed
65 The state diagrams below describe the status transitions.
66 Single arrows indicate that the thread that owns the node is
67 responsible for the transition; double arrows indicate that
68 any thread could make the transition.
70 State diagram for scoped_lock status:
72 waiting ----------> waiting_nonblocking
75 active -----------------> invalid
77 State diagram for scoped_lock_read status:
82 active ----------------->invalid
85 enum status_t { waiting_nonblocking, waiting, active, invalid };
87 //! Constructs a new reader_writer_lock
88 reader_writer_lock() {
92 //! Destructs a reader_writer_lock object
93 ~reader_writer_lock() {
97 //! The scoped lock pattern for write locks
98 /** Scoped locks help avoid the common problem of forgetting to release the lock.
99 This type also serves as the node for queuing locks. */
100 class scoped_lock : tbb::internal::no_copy {
102 friend class reader_writer_lock;
104 //! Construct with blocking attempt to acquire write lock on the passed-in lock
105 scoped_lock(reader_writer_lock& lock) {
106 internal_construct(lock);
109 //! Destructor, releases the write lock
114 void* operator new(size_t s) {
115 return tbb::internal::allocate_via_handler_v3(s);
117 void operator delete(void* p) {
118 tbb::internal::deallocate_via_handler_v3(p);
122 //! The pointer to the mutex to lock
123 reader_writer_lock *mutex;
124 //! The next queued competitor for the mutex
126 //! Status flag of the thread associated with this node
127 atomic<status_t> status;
129 //! Construct scoped_lock that is not holding lock
132 void __TBB_EXPORTED_METHOD internal_construct(reader_writer_lock&);
133 void __TBB_EXPORTED_METHOD internal_destroy();
136 //! The scoped lock pattern for read locks
137 class scoped_lock_read : tbb::internal::no_copy {
139 friend class reader_writer_lock;
141 //! Construct with blocking attempt to acquire read lock on the passed-in lock
142 scoped_lock_read(reader_writer_lock& lock) {
143 internal_construct(lock);
146 //! Destructor, releases the read lock
147 ~scoped_lock_read() {
151 void* operator new(size_t s) {
152 return tbb::internal::allocate_via_handler_v3(s);
154 void operator delete(void* p) {
155 tbb::internal::deallocate_via_handler_v3(p);
159 //! The pointer to the mutex to lock
160 reader_writer_lock *mutex;
161 //! The next queued competitor for the mutex
162 scoped_lock_read *next;
163 //! Status flag of the thread associated with this node
164 atomic<status_t> status;
166 //! Construct scoped_lock_read that is not holding lock
169 void __TBB_EXPORTED_METHOD internal_construct(reader_writer_lock&);
170 void __TBB_EXPORTED_METHOD internal_destroy();
173 //! Acquires the reader_writer_lock for write.
174 /** If the lock is currently held in write mode by another
175 context, the writer will block by spinning on a local
176 variable. Exceptions thrown: improper_lock The context tries
177 to acquire a reader_writer_lock that it already has write
179 void __TBB_EXPORTED_METHOD lock();
181 //! Tries to acquire the reader_writer_lock for write.
182 /** This function does not block. Return Value: True or false,
183 depending on whether the lock is acquired or not. If the lock
184 is already held by this acquiring context, try_lock() returns
186 bool __TBB_EXPORTED_METHOD try_lock();
188 //! Acquires the reader_writer_lock for read.
189 /** If the lock is currently held by a writer, this reader will
190 block and wait until the writers are done. Exceptions thrown:
191 improper_lock The context tries to acquire a
192 reader_writer_lock that it already has write ownership of. */
193 void __TBB_EXPORTED_METHOD lock_read();
195 //! Tries to acquire the reader_writer_lock for read.
196 /** This function does not block. Return Value: True or false,
197 depending on whether the lock is acquired or not. */
198 bool __TBB_EXPORTED_METHOD try_lock_read();
200 //! Releases the reader_writer_lock
201 void __TBB_EXPORTED_METHOD unlock();
204 void __TBB_EXPORTED_METHOD internal_construct();
205 void __TBB_EXPORTED_METHOD internal_destroy();
207 //! Attempts to acquire write lock
208 /** If unavailable, spins in blocking case, returns false in non-blocking case. */
209 bool start_write(scoped_lock *);
210 //! Sets writer_head to w and attempts to unblock
211 void set_next_writer(scoped_lock *w);
212 //! Relinquishes write lock to next waiting writer or group of readers
213 void end_write(scoped_lock *);
214 //! Checks if current thread holds write lock
215 bool is_current_writer();
217 //! Attempts to acquire read lock
218 /** If unavailable, spins in blocking case, returns false in non-blocking case. */
219 void start_read(scoped_lock_read *);
220 //! Unblocks pending readers
221 void unblock_readers();
222 //! Relinquishes read lock by decrementing counter; last reader wakes pending writer
225 //! The list of pending readers
226 atomic<scoped_lock_read*> reader_head;
227 //! The list of pending writers
228 atomic<scoped_lock*> writer_head;
229 //! The last node in the list of pending writers
230 atomic<scoped_lock*> writer_tail;
231 //! Writer that owns the mutex; tbb_thread::id() otherwise.
232 tbb_thread::id my_current_writer;
234 atomic<uintptr_t> rdr_count_and_flags; // used with __TBB_AtomicOR, which assumes uintptr_t
237 } // namespace interface5
239 using interface5::reader_writer_lock;
243 #include "internal/_warning_suppress_disable_notice.h"
244 #undef __TBB_reader_writer_lock_H_include_area
246 #endif /* __TBB_reader_writer_lock_H */