By Calum Grant
Transactional programming is about defining units of work
called transactions that either succeed completely, or can be rolled back
(undone) completely.
The purpose of transactions is to make it easy to recover from errors. If an
exception is thrown, the transaction is rolled back. Transactions make
error-recovery trivial since the programmer does not need to worry about leaving
the program in an inconsistent state.
The Atomic library declares transactions using RAII. For example:
atomic::vector<std::string> list1, list2;
void f(std::string const & x)
{
atomic::transaction tr;
list1.push_back(x);
list2.push_back(x);
tr.commit();
}
If an exception is thrown, the transaction rolls back list1
and list2, and the function has no side-effects.
Transactions can be nested, so even if an inner transaction succeeds, an outer
transaction can roll it back.
The Atomic library implements a variety of classes that can be rolled back to
any point in their past. These are: value, list, vector,
map, multimap, set, multiset, shared_ptr and
weak_ptr. The atomic containers are approximately 10% slower than the std
containers.
Transactions give a strong guarantee of exception-safety, without needing to
analyse a program in minute detail for exceptions.
For further reading see GotW #61: ACID Programming.