Transactional
Memory
We have already talked about some of the complexities of implementing a
functionally correct parallel application. One particular problem is that of
data races. In a large pro-gram, it can be quite hard to truly eliminate all
possible races. Even using data race detection tools does not guarantee that
there are no further races hidden in the code.
The safe software solution is to place mutex locks
around all potentially critical sections of code. The mutex locks ensure that
only a single thread can access the critical variables and hence that the
application will work correctly. However, mutex locks both impose a performance
penalty on access to the shared variables and also work only if all accesses to
the variables are protected by a common lock.
The idea of transactional memory is to attempt to
address both issues. Transactional memory is really aimed at the correctness
issue. If it can also make a difference to per-formance, that is an additional
benefit rather than a critical benefit.
Transactional memory enables the developer to protect
accesses to variables within a transaction. A transaction is a block of code that either completes successfully
or fails and does not then result in any change in system state.
A common syntax for transactions has not yet been
developed. One possibility is the use of the keyword atomic to wrap the entire transaction. Listing 10.25 shows an exam-ple of
this. The transaction moves a value from one location in an array to another.
The keyword atomic
indicates that the specified amount must be moved atomically between the two
locations in the array. Since transactions can fail, the atomic keyword must implicitly retry the transaction until it successfully
completes. The critical points here are first that the transaction cannot leave
the data in an unknown partially completed state and second that no other
process can see a partially completed transaction. This makes the use of the
keyword atomic
appropriate.
Listing 10.25 Accessing
Multiple Accounts in a Single Transaction
void
move( int from, int to, int value )
{
atomic
{
accounts[
from ] -= value;
accounts[ to ] += value;
}
}
Transactions will fail if any of the variables used
in the transaction are modified (or potentially read) by another thread. This
is where transactions can improve the safety of parallel code. If there is
another modification of a variable used in a transaction outside of that
transaction, the transaction will fail. It is not possible for the transaction
to com-plete in the presence of data races. This does not stop situations where
multiple threads access a variable outside of a transaction, but it does
eliminate problems with the granu-larity of locks or potential deadlock
situations.
Transactional memory can be
provided either in software using a library or at the hardware level. Hardware
transactional memory is the ideal. This is where during a trans-action,
hardware tracks any other accesses to variables used by the transaction and
aborts the transaction if necessary.
Software transactional memory is
provided by a library that ensures that the variables used in the transaction
are accessed atomically only. As such, it tends to have a much higher
implementation cost compared to hardware transactional memory. Providing
transactions in software can help address the correctness issue; however, it is
unlikely to do so in a way that also leads to performance gains over using any
other approach.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.