17.1.8 Reader-Writer Locking
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 [HW92], 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.
Other more-recent scalable
reader-writer locks [LLO09]
might avoid some or all of these problems.
- 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 [RHP+07] 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.
Of course, there might well be other non-obvious issues surrounding
combining TM with reader-writer locking, as there in fact were with
exclusive locking.
Paul E. McKenney
2011-12-16