Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
tbb::interface5::reader_writer_lock Class Reference

Writer-preference reader-writer lock with local-only spinning on readers. More...

#include <reader_writer_lock.h>

Inheritance diagram for tbb::interface5::reader_writer_lock:
Collaboration diagram for tbb::interface5::reader_writer_lock:

Classes

class  scoped_lock
 The scoped lock pattern for write locks. More...
 
class  scoped_lock_read
 The scoped lock pattern for read locks. More...
 

Public Types

enum  status_t { waiting_nonblocking, waiting, active, invalid }
 Status type for nodes associated with lock instances. More...
 

Public Member Functions

 reader_writer_lock ()
 Constructs a new reader_writer_lock. More...
 
 ~reader_writer_lock ()
 Destructs a reader_writer_lock object. More...
 
void __TBB_EXPORTED_METHOD lock ()
 Acquires the reader_writer_lock for write. More...
 
bool __TBB_EXPORTED_METHOD try_lock ()
 Tries to acquire the reader_writer_lock for write. More...
 
void __TBB_EXPORTED_METHOD lock_read ()
 Acquires the reader_writer_lock for read. More...
 
bool __TBB_EXPORTED_METHOD try_lock_read ()
 Tries to acquire the reader_writer_lock for read. More...
 
void __TBB_EXPORTED_METHOD unlock ()
 Releases the reader_writer_lock. More...
 

Private Member Functions

void __TBB_EXPORTED_METHOD internal_construct ()
 
void __TBB_EXPORTED_METHOD internal_destroy ()
 
bool start_write (scoped_lock *)
 Attempts to acquire write lock. More...
 
void set_next_writer (scoped_lock *w)
 Sets writer_head to w and attempts to unblock. More...
 
void end_write (scoped_lock *)
 Relinquishes write lock to next waiting writer or group of readers. More...
 
bool is_current_writer ()
 Checks if current thread holds write lock. More...
 
void start_read (scoped_lock_read *)
 Attempts to acquire read lock. More...
 
void unblock_readers ()
 Unblocks pending readers. More...
 
void end_read ()
 Relinquishes read lock by decrementing counter; last reader wakes pending writer. More...
 
- Private Member Functions inherited from tbb::internal::no_copy
 no_copy ()
 Allow default construction. More...
 

Private Attributes

atomic< scoped_lock_read * > reader_head
 The list of pending readers. More...
 
atomic< scoped_lock * > writer_head
 The list of pending writers. More...
 
atomic< scoped_lock * > writer_tail
 The last node in the list of pending writers. More...
 
tbb_thread::id my_current_writer
 Writer that owns the mutex; tbb_thread::id() otherwise. More...
 
atomic< uintptr_t > rdr_count_and_flags
 Status of mutex. More...
 

Friends

class scoped_lock
 
class scoped_lock_read
 

Detailed Description

Writer-preference reader-writer lock with local-only spinning on readers.

Loosely adapted from Mellor-Crummey and Scott pseudocode at http://www.cs.rochester.edu/research/synchronization/pseudocode/rw.html#s_wp

Definition at line 34 of file reader_writer_lock.h.

Member Enumeration Documentation

◆ status_t

Status type for nodes associated with lock instances.

waiting_nonblocking: the wait state for nonblocking lock instances; for writes, these transition straight to active states; for reads, these are unused.

waiting: the start and spin state for all lock instances; these will transition to active state when appropriate. Non-blocking write locks transition from this state to waiting_nonblocking immediately.

active: the active state means that the lock instance holds the lock; it will transition to invalid state during node deletion

invalid: the end state for all nodes; this is set in the destructor so if we encounter this state, we are looking at memory that has already been freed

The state diagrams below describe the status transitions. Single arrows indicate that the thread that owns the node is responsible for the transition; double arrows indicate that any thread could make the transition.

State diagram for scoped_lock status:

waiting -------—> waiting_nonblocking | _____________/ | V V V active --------------—> invalid

State diagram for scoped_lock_read status:

waiting | V active --------------—>invalid

Enumerator
waiting_nonblocking 
waiting 
active 
invalid 

Definition at line 74 of file reader_writer_lock.h.

Constructor & Destructor Documentation

◆ reader_writer_lock()

tbb::interface5::reader_writer_lock::reader_writer_lock ( )
inline

Constructs a new reader_writer_lock.

Definition at line 77 of file reader_writer_lock.h.

77  {
79  }
void __TBB_EXPORTED_METHOD internal_construct()

References internal_construct().

Here is the call graph for this function:

◆ ~reader_writer_lock()

tbb::interface5::reader_writer_lock::~reader_writer_lock ( )
inline

Destructs a reader_writer_lock object.

Definition at line 82 of file reader_writer_lock.h.

82  {
84  }
void __TBB_EXPORTED_METHOD internal_destroy()

References internal_destroy().

Here is the call graph for this function:

Member Function Documentation

◆ end_read()

void tbb::interface5::reader_writer_lock::end_read ( )
private

Relinquishes read lock by decrementing counter; last reader wakes pending writer.

Definition at line 286 of file reader_writer_lock.cpp.

286  {
287  ITT_NOTIFY(sync_releasing, this);
288  __TBB_ASSERT(rdr_count_and_flags >= RC_INCR, "unlock() called but no readers hold the lock.");
290 }
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p sync_releasing
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:120
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.
const uintptr_t RC_INCR

References __TBB_ASSERT, ITT_NOTIFY, tbb::interface5::RC_INCR, rdr_count_and_flags, and sync_releasing.

Referenced by unlock().

Here is the caller graph for this function:

◆ end_write()

void tbb::interface5::reader_writer_lock::end_write ( scoped_lock I)
private

Relinquishes write lock to next waiting writer or group of readers.

Definition at line 264 of file reader_writer_lock.cpp.

264  {
265  __TBB_ASSERT(I==writer_head, "Internal error: can't unlock a thread that is not holding the lock.");
267  ITT_NOTIFY(sync_releasing, this);
268  if (I->next) { // potentially more writers
269  writer_head = I->next;
270  writer_head->status = active;
271  }
272  else { // No more writers; clear writer flag, test reader interest flag
273  __TBB_ASSERT(writer_head, NULL);
275  unblock_readers();
276  }
277  writer_head.fetch_and_store(NULL);
278  if (I != writer_tail.compare_and_swap(NULL, I)) { // an incoming writer is in the process of being added
279  spin_wait_while_eq(I->next, (scoped_lock *)NULL); // wait for new writer to be added
280  __TBB_ASSERT(I->next, "There should be a node following the last writer.");
281  set_next_writer(I->next);
282  }
283  }
284 }
uintptr_t fetch_and_and(atomic< uintptr_t > &operand, uintptr_t value)
const uintptr_t RFLAG
tbb_thread::id my_current_writer
Writer that owns the mutex; tbb_thread::id() otherwise.
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id id
atomic< scoped_lock * > writer_head
The list of pending writers.
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
void unblock_readers()
Unblocks pending readers.
void set_next_writer(scoped_lock *w)
Sets writer_head to w and attempts to unblock.
const uintptr_t WFLAG1
void spin_wait_while_eq(const volatile T &location, U value)
Spin WHILE the value of the variable is equal to a given value.
Definition: tbb_machine.h:395
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p sync_releasing
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:120
atomic< scoped_lock * > writer_tail
The last node in the list of pending writers.
const uintptr_t WFLAG2
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.

References __TBB_ASSERT, active, tbb::interface5::fetch_and_and(), id, ITT_NOTIFY, my_current_writer, tbb::interface5::reader_writer_lock::scoped_lock::next, rdr_count_and_flags, tbb::interface5::RFLAG, set_next_writer(), tbb::internal::spin_wait_while_eq(), sync_releasing, unblock_readers(), tbb::interface5::WFLAG1, tbb::interface5::WFLAG2, writer_head, and writer_tail.

Referenced by unlock().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ internal_construct()

void tbb::interface5::reader_writer_lock::internal_construct ( )
private

Definition at line 75 of file reader_writer_lock.cpp.

75  {
76  reader_head = NULL;
77  writer_head = NULL;
78  writer_tail = NULL;
81 #if TBB_USE_THREADING_TOOLS
82  ITT_SYNC_CREATE(this, _T("tbb::reader_writer_lock"), _T(""));
83 #endif /* TBB_USE_THREADING_TOOLS */
84 }
tbb_thread::id my_current_writer
Writer that owns the mutex; tbb_thread::id() otherwise.
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id id
atomic< scoped_lock * > writer_head
The list of pending writers.
#define ITT_SYNC_CREATE(obj, type, name)
Definition: itt_notify.h:123
atomic< scoped_lock_read * > reader_head
The list of pending readers.
#define _T(string_literal)
Standard Windows style macro to markup the string literals.
Definition: itt_notify.h:66
atomic< scoped_lock * > writer_tail
The last node in the list of pending writers.
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.

References _T, id, ITT_SYNC_CREATE, my_current_writer, rdr_count_and_flags, reader_head, writer_head, and writer_tail.

Referenced by reader_writer_lock().

Here is the caller graph for this function:

◆ internal_destroy()

void tbb::interface5::reader_writer_lock::internal_destroy ( )
private

Definition at line 86 of file reader_writer_lock.cpp.

86  {
87  __TBB_ASSERT(rdr_count_and_flags==0, "reader_writer_lock destroyed with pending readers/writers.");
88  __TBB_ASSERT(reader_head==NULL, "reader_writer_lock destroyed with pending readers.");
89  __TBB_ASSERT(writer_tail==NULL, "reader_writer_lock destroyed with pending writers.");
90  __TBB_ASSERT(writer_head==NULL, "reader_writer_lock destroyed with pending/active writers.");
91 }
atomic< scoped_lock * > writer_head
The list of pending writers.
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
atomic< scoped_lock_read * > reader_head
The list of pending readers.
atomic< scoped_lock * > writer_tail
The last node in the list of pending writers.
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.

References __TBB_ASSERT, rdr_count_and_flags, reader_head, writer_head, and writer_tail.

Referenced by ~reader_writer_lock().

Here is the caller graph for this function:

◆ is_current_writer()

bool tbb::interface5::reader_writer_lock::is_current_writer ( )
inlineprivate

Checks if current thread holds write lock.

Definition at line 292 of file reader_writer_lock.cpp.

292  {
294 }
tbb_thread::id my_current_writer
Writer that owns the mutex; tbb_thread::id() otherwise.
tbb_thread::id get_id()
Definition: tbb_thread.h:321

References tbb::this_tbb_thread::get_id(), and my_current_writer.

Referenced by lock(), lock_read(), try_lock(), try_lock_read(), and unlock().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lock()

void tbb::interface5::reader_writer_lock::lock ( )

Acquires the reader_writer_lock for write.

If the lock is currently held in write mode by another context, the writer will block by spinning on a local variable. Exceptions thrown: improper_lock The context tries to acquire a reader_writer_lock that it already has write ownership of.

Definition at line 97 of file reader_writer_lock.cpp.

97  {
98  if (is_current_writer()) { // recursive lock attempt
99  // we don't support recursive writer locks; throw exception
101  }
102  else {
103  scoped_lock *a_writer_lock = new scoped_lock();
104  (void) start_write(a_writer_lock);
105  }
106 }
bool start_write(scoped_lock *)
Attempts to acquire write lock.
bool is_current_writer()
Checks if current thread holds write lock.
void throw_exception(exception_id eid)
Versionless convenience wrapper for throw_exception_v4()

References tbb::internal::eid_improper_lock, is_current_writer(), scoped_lock, start_write(), tbb::internal::throw_exception(), and void.

Referenced by tbb::interface5::reader_writer_lock::scoped_lock::internal_construct(), tbb::interface5::reader_writer_lock::scoped_lock_read::internal_construct(), tbb::interface5::reader_writer_lock::scoped_lock::scoped_lock(), and tbb::interface5::reader_writer_lock::scoped_lock_read::scoped_lock_read().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lock_read()

void tbb::interface5::reader_writer_lock::lock_read ( )

Acquires the reader_writer_lock for read.

If the lock is currently held by a writer, this reader will block and wait until the writers are done. Exceptions thrown: improper_lock The context tries to acquire a reader_writer_lock that it already has write ownership of.

Definition at line 184 of file reader_writer_lock.cpp.

184  {
185  if (is_current_writer()) { // recursive lock attempt
186  // we don't support writer->reader downgrade; throw exception
188  }
189  else {
190  scoped_lock_read a_reader_lock;
191  start_read(&a_reader_lock);
192  }
193 }
void start_read(scoped_lock_read *)
Attempts to acquire read lock.
bool is_current_writer()
Checks if current thread holds write lock.
void throw_exception(exception_id eid)
Versionless convenience wrapper for throw_exception_v4()

References tbb::internal::eid_improper_lock, is_current_writer(), start_read(), and tbb::internal::throw_exception().

Here is the call graph for this function:

◆ set_next_writer()

void tbb::interface5::reader_writer_lock::set_next_writer ( scoped_lock w)
private

Sets writer_head to w and attempts to unblock.

Definition at line 161 of file reader_writer_lock.cpp.

161  {
162  writer_head = W;
163  if (W->status == waiting_nonblocking) {
165  W->status = active;
166  }
167  }
168  else {
169  if (fetch_and_or(rdr_count_and_flags, WFLAG1) & RFLAG) { // reader present
170  spin_wait_until_and(rdr_count_and_flags, WFLAG2); // block until readers set WFLAG2
171  }
172  else { // no reader in timing window
174  }
175  spin_wait_while_geq(rdr_count_and_flags, RC_INCR); // block until readers finish
176  W->status = active;
177  }
178 }
const uintptr_t RFLAG
atomic< scoped_lock * > writer_head
The list of pending writers.
const uintptr_t WFLAG1
void spin_wait_while_geq(const volatile T &location, U value)
Spin WHILE the value at the location is greater than or equal to a given value.
value_type compare_and_swap(value_type value, value_type comparand)
Definition: atomic.h:289
uintptr_t fetch_and_or(atomic< uintptr_t > &operand, uintptr_t value)
const uintptr_t WFLAG2
void spin_wait_until_and(const volatile T &location, U value)
Spin UNTIL (location & value) is true.
void __TBB_AtomicOR(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:882
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.
const uintptr_t RC_INCR

References __TBB_AtomicOR(), active, tbb::internal::atomic_impl< T >::compare_and_swap(), tbb::interface5::fetch_and_or(), tbb::interface5::RC_INCR, rdr_count_and_flags, tbb::interface5::RFLAG, tbb::interface5::spin_wait_until_and(), tbb::interface5::spin_wait_while_geq(), tbb::interface5::reader_writer_lock::scoped_lock::status, waiting_nonblocking, tbb::interface5::WFLAG1, tbb::interface5::WFLAG2, and writer_head.

Referenced by end_write(), and start_write().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_read()

void tbb::interface5::reader_writer_lock::start_read ( scoped_lock_read I)
private

Attempts to acquire read lock.

If unavailable, spins in blocking case, returns false in non-blocking case.

Definition at line 213 of file reader_writer_lock.cpp.

213  {
214  ITT_NOTIFY(sync_prepare, this);
215  I->next = reader_head.fetch_and_store(I);
216  if (!I->next) { // first arriving reader in my group; set RFLAG, test writer flags
217  // unblock and/or update statuses of non-blocking readers
218  if (!(fetch_and_or(rdr_count_and_flags, RFLAG) & (WFLAG1+WFLAG2))) { // no writers
219  unblock_readers();
220  }
221  }
222  __TBB_ASSERT(I->status == waiting || I->status == active, "Lock requests should be waiting or active before blocking.");
223  spin_wait_while_eq(I->status, waiting); // block
224  if (I->next) {
225  __TBB_ASSERT(I->next->status == waiting, NULL);
227  I->next->status = active; // wake successor
228  }
229  ITT_NOTIFY(sync_acquired, this);
230 }
const uintptr_t RFLAG
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
void unblock_readers()
Unblocks pending readers.
atomic< scoped_lock_read * > reader_head
The list of pending readers.
const uintptr_t WFLAG1
void spin_wait_while_eq(const volatile T &location, U value)
Spin WHILE the value of the variable is equal to a given value.
Definition: tbb_machine.h:395
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:120
uintptr_t fetch_and_or(atomic< uintptr_t > &operand, uintptr_t value)
const uintptr_t WFLAG2
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.
const uintptr_t RC_INCR

References __TBB_ASSERT, active, tbb::interface5::fetch_and_or(), ITT_NOTIFY, tbb::interface5::reader_writer_lock::scoped_lock_read::next, tbb::interface5::RC_INCR, rdr_count_and_flags, reader_head, tbb::interface5::RFLAG, tbb::internal::spin_wait_while_eq(), tbb::interface5::reader_writer_lock::scoped_lock_read::status, unblock_readers(), waiting, tbb::interface5::WFLAG1, and tbb::interface5::WFLAG2.

Referenced by lock_read().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_write()

bool tbb::interface5::reader_writer_lock::start_write ( scoped_lock I)
private

Attempts to acquire write lock.

If unavailable, spins in blocking case, returns false in non-blocking case.

Definition at line 122 of file reader_writer_lock.cpp.

122  {
124  scoped_lock *pred = NULL;
125  if (I->status == waiting_nonblocking) {
126  if ((pred = writer_tail.compare_and_swap(I, NULL)) != NULL) {
127  delete I;
128  return false;
129  }
130  }
131  else {
132  ITT_NOTIFY(sync_prepare, this);
133  pred = writer_tail.fetch_and_store(I);
134  }
135  if (pred)
136  pred->next = I;
137  else {
138  set_next_writer(I);
139  if (I->status == waiting_nonblocking) {
140  if (I->next) { // potentially more writers
141  set_next_writer(I->next);
142  }
143  else { // no more writers
144  writer_head.fetch_and_store(NULL);
145  if (I != writer_tail.compare_and_swap(NULL, I)) { // an incoming writer is in the process of being added
146  spin_wait_while_eq(I->next, (scoped_lock *)NULL); // wait for new writer to be added
147  __TBB_ASSERT(I->next, "There should be a node following the last writer.");
148  set_next_writer(I->next);
149  }
150  }
151  delete I;
152  return false;
153  }
154  }
155  spin_wait_while_eq(I->status, waiting);
156  ITT_NOTIFY(sync_acquired, this);
158  return true;
159 }
tbb_thread::id my_current_writer
Writer that owns the mutex; tbb_thread::id() otherwise.
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id id
atomic< scoped_lock * > writer_head
The list of pending writers.
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
void set_next_writer(scoped_lock *w)
Sets writer_head to w and attempts to unblock.
void spin_wait_while_eq(const volatile T &location, U value)
Spin WHILE the value of the variable is equal to a given value.
Definition: tbb_machine.h:395
tbb_thread::id get_id()
Definition: tbb_thread.h:321
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:120
atomic< scoped_lock * > writer_tail
The last node in the list of pending writers.

References __TBB_ASSERT, tbb::this_tbb_thread::get_id(), id, ITT_NOTIFY, my_current_writer, tbb::interface5::reader_writer_lock::scoped_lock::next, set_next_writer(), tbb::internal::spin_wait_while_eq(), tbb::interface5::reader_writer_lock::scoped_lock::status, waiting, waiting_nonblocking, writer_head, and writer_tail.

Referenced by lock(), and try_lock().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_lock()

bool tbb::interface5::reader_writer_lock::try_lock ( )

Tries to acquire the reader_writer_lock for write.

This function does not block. Return Value: True or false, depending on whether the lock is acquired or not. If the lock is already held by this acquiring context, try_lock() returns false.

Definition at line 111 of file reader_writer_lock.cpp.

111  {
112  if (is_current_writer()) { // recursive lock attempt
113  return false;
114  }
115  else {
116  scoped_lock *a_writer_lock = new scoped_lock();
117  a_writer_lock->status = waiting_nonblocking;
118  return start_write(a_writer_lock);
119  }
120 }
bool start_write(scoped_lock *)
Attempts to acquire write lock.
bool is_current_writer()
Checks if current thread holds write lock.

References is_current_writer(), scoped_lock, start_write(), tbb::interface5::reader_writer_lock::scoped_lock::status, and waiting_nonblocking.

Here is the call graph for this function:

◆ try_lock_read()

bool tbb::interface5::reader_writer_lock::try_lock_read ( )

Tries to acquire the reader_writer_lock for read.

This function does not block. Return Value: True or false, depending on whether the lock is acquired or not.

Definition at line 197 of file reader_writer_lock.cpp.

197  {
198  if (is_current_writer()) { // recursive lock attempt
199  return false;
200  }
201  else {
202  if (rdr_count_and_flags.fetch_and_add(RC_INCR) & (WFLAG1+WFLAG2)) { // writers present
204  return false;
205  }
206  else { // no writers
207  ITT_NOTIFY(sync_acquired, this);
208  return true;
209  }
210  }
211 }
bool is_current_writer()
Checks if current thread holds write lock.
const uintptr_t WFLAG1
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:120
const uintptr_t WFLAG2
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.
const uintptr_t RC_INCR

References is_current_writer(), ITT_NOTIFY, tbb::interface5::RC_INCR, rdr_count_and_flags, tbb::interface5::WFLAG1, and tbb::interface5::WFLAG2.

Here is the call graph for this function:

◆ unblock_readers()

void tbb::interface5::reader_writer_lock::unblock_readers ( )
private

Unblocks pending readers.

Definition at line 232 of file reader_writer_lock.cpp.

232  {
233  // clear rdr interest flag, increment rdr count
237  // indicate clear of window
240  }
241  // unblock waiting readers
242  scoped_lock_read *head = reader_head.fetch_and_store(NULL);
243  __TBB_ASSERT(head, NULL);
244  __TBB_ASSERT(head->status == waiting, NULL);
245  head->status = active;
246 }
const uintptr_t RFLAG
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type size_t void ITT_FORMAT p const __itt_domain __itt_id __itt_string_handle const wchar_t size_t ITT_FORMAT lu const __itt_domain __itt_id head
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
atomic< scoped_lock_read * > reader_head
The list of pending readers.
const uintptr_t WFLAG1
const uintptr_t WFLAG2
void __TBB_AtomicOR(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:882
atomic< uintptr_t > rdr_count_and_flags
Status of mutex.
const uintptr_t RC_INCR

References __TBB_ASSERT, __TBB_AtomicOR(), active, head, tbb::interface5::RC_INCR, rdr_count_and_flags, reader_head, tbb::interface5::RFLAG, waiting, tbb::interface5::WFLAG1, and tbb::interface5::WFLAG2.

Referenced by end_write(), and start_read().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ unlock()

void tbb::interface5::reader_writer_lock::unlock ( )

Releases the reader_writer_lock.

Definition at line 249 of file reader_writer_lock.cpp.

249  {
251  // A writer owns the lock
252  __TBB_ASSERT(is_current_writer(), "caller of reader_writer_lock::unlock() does not own the lock.");
253  __TBB_ASSERT(writer_head, NULL);
254  __TBB_ASSERT(writer_head->status==active, NULL);
255  scoped_lock *a_writer_lock = writer_head;
256  end_write(a_writer_lock);
257  __TBB_ASSERT(a_writer_lock != writer_head, "Internal error: About to turn writer_head into dangling reference.");
258  delete a_writer_lock;
259  } else {
260  end_read();
261  }
262 }
tbb_thread::id my_current_writer
Writer that owns the mutex; tbb_thread::id() otherwise.
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id id
atomic< scoped_lock * > writer_head
The list of pending writers.
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
bool is_current_writer()
Checks if current thread holds write lock.
void end_read()
Relinquishes read lock by decrementing counter; last reader wakes pending writer.
void end_write(scoped_lock *)
Relinquishes write lock to next waiting writer or group of readers.

References __TBB_ASSERT, active, end_read(), end_write(), id, is_current_writer(), my_current_writer, and writer_head.

Here is the call graph for this function:

Friends And Related Function Documentation

◆ scoped_lock

friend class scoped_lock
friend

Definition at line 36 of file reader_writer_lock.h.

Referenced by lock(), and try_lock().

◆ scoped_lock_read

friend class scoped_lock_read
friend

Definition at line 37 of file reader_writer_lock.h.

Member Data Documentation

◆ my_current_writer

tbb_thread::id tbb::interface5::reader_writer_lock::my_current_writer
private

Writer that owns the mutex; tbb_thread::id() otherwise.

Definition at line 221 of file reader_writer_lock.h.

Referenced by end_write(), internal_construct(), is_current_writer(), start_write(), and unlock().

◆ rdr_count_and_flags

atomic<uintptr_t> tbb::interface5::reader_writer_lock::rdr_count_and_flags
private

◆ reader_head

atomic<scoped_lock_read*> tbb::interface5::reader_writer_lock::reader_head
private

The list of pending readers.

Definition at line 215 of file reader_writer_lock.h.

Referenced by internal_construct(), internal_destroy(), start_read(), and unblock_readers().

◆ writer_head

atomic<scoped_lock*> tbb::interface5::reader_writer_lock::writer_head
private

The list of pending writers.

Definition at line 217 of file reader_writer_lock.h.

Referenced by end_write(), internal_construct(), internal_destroy(), set_next_writer(), start_write(), and unlock().

◆ writer_tail

atomic<scoped_lock*> tbb::interface5::reader_writer_lock::writer_tail
private

The last node in the list of pending writers.

Definition at line 219 of file reader_writer_lock.h.

Referenced by end_write(), internal_construct(), internal_destroy(), and start_write().


The documentation for this class was generated from the following files:

Copyright © 2005-2019 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.