WriterReaderPhaser provides an asymmetric means for
synchronizing the execution of wait-free "writer" critical sections against
a "reader phase flip" that needs to make sure no writer critical sections
that were active at the beginning of the flip are still active after the
flip is done. Multiple writers and multiple readers are supported.
Using a WriterReaderPhaser for coordination, writers can continously
perform wait-free/lock-free updates to common data structures, while readers
can get hold of atomic and inactive snapshots without stalling writers.
While a WriterReaderPhaser can be useful in multiple scenarios, a
specific and common use case is that of safely managing "double buffered"
data stream access in which writers can proceed without being blocked, while
readers gain access to stable and unchanging buffer samples.
WriterReaderPhaser "writers" are wait free (on architectures that support
wait free atomic increment operations), "readers" block for other
"readers", and "readers" are only blocked by "writers" whose critical section
was entered before the reader's
WriterReaderPhaser#flipPhase() attempt.
When used to protect an actively recording data structure, the assumptions on how readers and writers act are:
WriterReaderPhaser#writerCriticalSectionEnter and
writerCriticalSectionExit().
WriterReaderPhaser#readerLock()
protection and only before calling WriterReaderPhaser#flipPhase().WriterReaderPhaser#writerCriticalSectionEnter
and
writerCriticalSectionExit().
WriterReaderPhaser#readerLock() and
WriterReaderPhaser#readerUnlock().WriterReaderPhaser#flipPhase() operations,
and only while holding the readerLock.
When the above assumptions are met, WriterReaderPhaser guarantees
that the inactive data structures are not being modified by any writers while
being read while under readerLock() protection after a
WriterReaderPhaser#flipPhase()() operation.
The following progress guarantees are provided to writers and readers that adhere to the above stated assumptions:
writerCriticalSectionEnter
and writerCriticalSectionExit)
are wait free on architectures that
support wait-free atomic increment operations (they remain lock-free [but not
wait-free] on architectures that do not support wait-free atomic increment
operations)WriterReaderPhaser#flipPhase() operations are guaranteed to
make forward progress, and will only be blocked by writers whose critical sections
were entered prior to the start of the reader's flipPhase operation, and have not
yet exited their critical sections.WriterReaderPhaser#readerLock() only blocks for other
readers that are holding the readerLock.
final WriterReaderPhaser recordingPhaser = new WriterReaderPhaser();
volatile Histogram activeHistogram;
Histogram inactiveHistogram;
...
A writer may record values the histogram:
// Wait-free recording:
long criticalValueAtEnter = recordingPhaser.writerCriticalSectionEnter();
try {
activeHistogram.recordValue(value);
} finally {
recordingPhaser.writerCriticalSectionExit(criticalValueAtEnter);
}
A reader gains access to a stable histogram of values recorded during an interval,
and reports on it:
try {
recordingPhaser.readerLock();
inactiveHistogram.reset();
// Swap active and inactive histograms:
final Histogram tempHistogram = inactiveHistogram;
inactiveHistogram = activeHistogram;
activeHistogram = tempHistogram;
recordingPhaser.flipPhase();
// At this point, inactiveHistogram content is guaranteed to be stable
logHistogram(inactiveHistogram);
} finally {
recordingPhaser.readerUnlock();
}
| Modifier and Type | Field and Description |
|---|---|
| private volatile long | |
| private static final AtomicLongFieldUpdater | |
| private volatile long | |
| private static final AtomicLongFieldUpdater | |
| private final ReentrantLock | |
| private volatile long | |
| private static final AtomicLongFieldUpdater |
| Access | Constructor and Description |
|---|---|
| public |
| Modifier and Type | Method and Description |
|---|---|
| public void | flipPhase(long
The amount of time (in nanoseconds) to sleep in each yield if yield loop is needed. yieldTimeNsec)Flip a phase in the |
| public void | flipPhase()
Flip a phase in the |
| public void | readerLock()
Enter to a critical section containing a read operation (reentrant, mutually excludes against
|
| public void | readerUnlock()
Exit from a critical section containing a read operation (relinquishes mutual exclusion against other
|
| public long | Returns: an (opaque) value associated with the critical section entry, which MUST be provided to the matchingWriterReaderPhaser#writerCriticalSectionExit call.Indicate entry to a critical section containing a write operation. |
| public void | writerCriticalSectionExit(long
the (opaque) value returned from the matching
criticalValueAtEnter)WriterReaderPhaser#writerCriticalSectionEnter() call.Indicate exit from a critical section containing a write operation. |
| evenEndEpoch | back to summary |
|---|---|
| private volatile long evenEndEpoch | |
| evenEndEpochUpdater | back to summary |
|---|---|
| private static final AtomicLongFieldUpdater<WriterReaderPhaser> evenEndEpochUpdater | |
| oddEndEpoch | back to summary |
|---|---|
| private volatile long oddEndEpoch | |
| oddEndEpochUpdater | back to summary |
|---|---|
| private static final AtomicLongFieldUpdater<WriterReaderPhaser> oddEndEpochUpdater | |
| readerLock | back to summary |
|---|---|
| private final ReentrantLock readerLock | |
| startEpoch | back to summary |
|---|---|
| private volatile long startEpoch | |
| startEpochUpdater | back to summary |
|---|---|
| private static final AtomicLongFieldUpdater<WriterReaderPhaser> startEpochUpdater | |
| WriterReaderPhaser | back to summary |
|---|---|
| public WriterReaderPhaser() | |
| flipPhase | back to summary |
|---|---|
| public void flipPhase(long yieldTimeNsec) Flip a phase in the
No actual writer critical section activity is required for
However,
| |
| flipPhase | back to summary |
|---|---|
| public void flipPhase() Flip a phase in the
No actual writer critical section activity is required for
However, | |
| readerLock | back to summary |
|---|---|
| public void readerLock() Enter to a critical section containing a read operation (reentrant, mutually excludes against
| |
| readerUnlock | back to summary |
|---|---|
| public void readerUnlock() Exit from a critical section containing a read operation (relinquishes mutual exclusion against other
| |
| writerCriticalSectionEnter | back to summary |
|---|---|
| public long writerCriticalSectionEnter() Indicate entry to a critical section containing a write operation. This call is wait-free on architectures that support wait free atomic increment operations, and is lock-free on architectures that do not.
| |
| writerCriticalSectionExit | back to summary |
|---|---|
| public void writerCriticalSectionExit(long criticalValueAtEnter) Indicate exit from a critical section containing a write operation. This call is wait-free on architectures that support wait free atomic increment operations, and is lock-free on architectures that do not.
| |