Reader-Writer Locking Within Transactions
It is commonplace to read-acquire reader-writer locks while holding
other locks, which just works,
at least as long as the usual well-known software-engineering techniques
are employed to avoid deadlock.
Read-acquiring reader-writer locks from within RCU read-side critical
sections also works, and doing so eases deadlock concerns because
RCU read-side primitives cannot participated in lock-based deadlock cycles.
But what happens when you attempt to read-acquire a reader-writer lock from
within a transaction?
Unfortunately, the straightforward approach to read-acquiring the
traditional counter-based
reader-writer lock within a transaction defeats the purpose of
the reader-writer lock.
To see this, consider a pair of transactions concurrently attempting
to read-acquire the same reader-writer lock.
Because read-acquisition involves modifying the reader-writer lock's
data structures, a conflict will result, which will roll back
one of the two transactions.
This behavior is completely inconsistent with the reader-writer lock's
goal of allowing concurrent readers.
Here are some options available to TM:
- Use per-CPU or per-thread reader-writer locking,
which allows a given CPU (or thread, respectively) to manipulate
only local data when read-acquiring the lock.
This would avoid the conflict between the two transactions
concurrently read-acquiring the lock, permitting both to
proceed, as intended.
Unfortunately, (1) the write-acquisition overhead of per-CPU/thread
locking can be extremely high, (2) the memory overhead of
per-CPU/thread locking can be prohibitive, and (3) this
transformation is available only when you have access to the
source code in question.
- Use TM only “in the small” when introducing TM
to lock-based programs, thereby avoiding read-acquiring
reader-writer locks from within transactions.
- Set aside locking-based legacy systems entirely, re-implementing
everything in terms of transactions.
This approach has no shortage of advocates, but this requires that
all the issues described in this series be resolved.
During the time it takes to resolve these issues, competing
synchronization mechanisms will of course also have the opportunity to
improve.
- Use TM strictly as an optimization in lock-based systems,
as was done by the
TxLinux group.
This approach seems sound, but leaves the locking design constraints
(such as the need to avoid deadlock) firmly in place.
Furthermore, this approach can result in unnecessary transaction
rollbacks when multiple transactions attempt to read-acquire
the same lock.
There might well be other non-obvious issues surrounding combining
TM with reader-writer locking, as there in fact were with exclusive locking.