Ami Tavory Ami Tavory - 3 months ago 9
C++ Question

Generic Components Friendly To Software Transactional Memory

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.

Answer

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.

Comments