Say we write some new class which can be used concurrently or not. Obviously, we don't want to have locks on everything on the chance that they will be called concurrently. One way to address this is through parameterizing by mixins specifying locking:
template<class Locking>
struct foo : private Locking {
void bar() {
Locking::read_lock();
// Do something.
Locking::read_unlock();
}
};
and instantiating Locking
with a class that actually locks for the multithreading case, and with a class that does no-ops for the other case (hopefully, the compiler will even optimize away the calls).
Now suppose I'd like to do this with software-transactional memory instead of locking. Looking at N3919 (or the gcc precursor), the idea is different. There are no calls such as
transaction_start();
transaction_end();
Instead there are function specifiers like
void bar() transaction_safe;
and block specifiers like
transaction { /* body */ }
with strict rules of the latter calling the former, and nothing that looks like it can be used by mixins.
How can this be done(without involving the preprocessor)? Note also that one of the main benefits of STM is composability, but there seems no way to get the instantiation to reflect that bar
is transactionable.
In a similar way, with lambda, it seems you may do something like:
template<class Transaction>
struct foo {
void bar() {
Transaction::run([](){ /* Do something. */ });
}
};
with the 2 implementations
template<typename F>
void TransactionNone::run(F f) { f(); }
and
template<typename F>
void TransactionReal::run(F f) { transaction{ f(); } }
For attributes,
A function is transaction-safe if it is not transaction-unsafe.
So it seems you may omit that keyword, and let the compiler/linker do that job.