Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

transactional memory idea

153 views
Skip to first unread message

Bonita Montero

unread,
Jan 17, 2020, 3:10:42 AM1/17/20
to
I just had a little idea to abstract intel TSX from the
code within a transaction:

template<typename L>
inline
bool transaction( L &lambda )
{
if( _xbegin() == _XBEGIN_STARTED )
{
lambda();
_xend();
return true;
}
else
return false;
}


auto syncedOp = [...]( ... ) { ... };
while( !transaction<decltype(syncedOp)>( syncedOp ) );

Intel has TSX and IBM has something similar with the POWER-CPUs
so that this could be identically abstracted.
And CPUs not having something like this could have a #ifdef code
-path in transaction<>() that uses usual locking on a static mutex
inside transaction<>() and return true in every case.

Another issue: why do I have to write decltype(syncedOp) or why
is C++ too stupid to deduce the lambda-type itself. If it could
I could write the lambda directly in the function-call.

Bonita Montero

unread,
Jan 17, 2020, 8:40:45 AM1/17/20
to
Am 17.01.2020 um 09:10 schrieb Bonita Montero:
> I just had a little idea to abstract intel TSX from the
> code within a transaction:
>
> template<typename L>
> inline
> bool transaction( L &lambda )
> {
>     if( _xbegin() == _XBEGIN_STARTED )
>     {
>         lambda();
>         _xend();
>         return true;
>    }
>    else
>         return false;
> }

This should be better:


template<typename L>
inline
int transaction( L &lambda )
{
unsinged code = _xbegin();
if( code == _XBEGIN_STARTED )
{
lambda();
_xend();
return 1;
}
else
return code & _XABORT_RETRY ? 0 : -1;
}

Alf P. Steinbach

unread,
Jan 17, 2020, 2:31:26 PM1/17/20
to
On 17.01.2020 14:40, Bonita Montero wrote:
> Am 17.01.2020 um 09:10 schrieb Bonita Montero:
>> I just had a little idea to abstract intel TSX from the
>> code within a transaction:
>>
>> template<typename L>
>> inline
>> bool transaction( L &lambda )
>> {
>>      if( _xbegin() == _XBEGIN_STARTED )
>>      {
>>          lambda();
>>          _xend();
>>          return true;
>>     }
>>     else
>>          return false;
>> }

Don't pass the lambda by reference to non-`const`, because that requires
the caller to have a lambda /variable/.

Use RAII (destructor) to ensure that `_xend()` is called even if the
lambda throws an exception.

If you don't care to define small RAII classes all over the place,
consider using a general one such as gsl::action, <url:
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c30-define-a-destructor-if-a-class-needs-an-explicit-action-at-object-destruction>

> This should be better:
>
>
> template<typename L>
> inline
> int transaction( L &lambda )
> {
>     unsinged code = _xbegin();
>     if( code == _XBEGIN_STARTED )
>     {
>         lambda();
>         _xend();
>         return 1;
>     }
>     else
>         return code & _XABORT_RETRY ? 0 : -1;
> }

It seems unlikely that the above could be a callback function with a
signature required by third party code that you don't control.

So, don't use `int` where `bool` (or better, a less conversion-eager
wrapper of `bool`) is more appropriate.

Example of a `bool` wrapper: <url:
https://github.com/alf-p-steinbach/cppx-core-language/blob/master/source/cppx-core-language/types/Truth.hpp>

Don't use a choice operator or conditional expression to compute a
boolean value when you can directly use a boolean expression.


Just my 2c,

- Alf

Bonita Montero

unread,
Jan 17, 2020, 2:51:35 PM1/17/20
to
>> Am 17.01.2020 um 09:10 schrieb Bonita Montero:
>>> I just had a little idea to abstract intel TSX from the
>>> code within a transaction:
>>>
>>> template<typename L>
>>> inline
>>> bool transaction( L &lambda )
>>> {
>>>      if( _xbegin() == _XBEGIN_STARTED )
>>>      {
>>>          lambda();
>>>          _xend();
>>>          return true;
>>>     }
>>>     else
>>>          return false;
>>> }

> Don't pass the lambda by reference to non-`const`, because that requires
> the caller to have a lambda /variable/.

Why should this be a problem ?

> Use RAII (destructor) to ensure that `_xend()` is called even if the
> lambda throws an exception.

In an transaction you wouldn't do some RAII-ish things anyway but
just simple things like some pointer-adjustments in a data-strcuture.
Having fully RAII-conformance might grow the transaction working-set
too large.

> It seems unlikely that the above could be a callback function with
> a signature required by third party code that you don't control.
> So, don't use `int` where `bool` (or better, a less conversion-eager
> wrapper of `bool`) is more appropriate.
> Don't use a choice operator or conditional expression to compute
> a boolean value when you can directly use a boolean expression.

There are three states: transaction successful, transaction aborted but
could be restarted and transaction aborted and can't be restarted due to
cache-overflow (the l1 couldn't track the whole transaction). How should
I do that with a bool which can hold two states ?

Bonita Montero

unread,
Jan 17, 2020, 2:53:18 PM1/17/20
to
Ultimatively stupid stuff.
If you don't like implicit conversion in C++ chose another language.

Alf P. Steinbach

unread,
Jan 17, 2020, 3:36:53 PM1/17/20
to
On 17.01.2020 20:51, Bonita Montero wrote:
>>> Am 17.01.2020 um 09:10 schrieb Bonita Montero:
>>>> I just had a little idea to abstract intel TSX from the
>>>> code within a transaction:
>>>>
>>>> template<typename L>
>>>> inline
>>>> bool transaction( L &lambda )
>>>> {
>>>>      if( _xbegin() == _XBEGIN_STARTED )
>>>>      {
>>>>          lambda();
>>>>          _xend();
>>>>          return true;
>>>>     }
>>>>     else
>>>>          return false;
>>>> }
>
>> Don't pass the lambda by reference to non-`const`, because that
>> requires the caller to have a lambda /variable/.
>
> Why should this be a problem ?

It imposes needless verbosity and bug vectors on the calling code.


>> Use RAII (destructor) to ensure that `_xend()` is called even if the
>> lambda throws an exception.
>
> In an transaction you wouldn't do some RAII-ish things anyway but
> just simple things like some pointer-adjustments in a data-strcuture.
> Having fully RAII-conformance might grow the transaction working-set
> too large.

No, there is no connection between the way you do cleanup (unsafely, or
as I propose safely) and the transaction working set.


>> It seems unlikely that the above could be a callback function with
>> a signature required by third party code that you don't control.
>> So, don't use `int` where `bool` (or better, a less conversion-eager
>> wrapper of `bool`) is more appropriate.
> > Don't use a choice operator or conditional expression to compute
> > a boolean value when you can directly use a boolean expression.
>
> There are three states: transaction successful, transaction aborted but
> could be restarted and transaction aborted and can't be restarted due to
> cache-overflow (the l1 couldn't track the whole transaction). How should
> I do that with a bool which can hold two states ?

In the same way as your current code which you snipped, which returns
either 0 or 1.

- Alf

Chris M. Thomasson

unread,
Jan 17, 2020, 6:49:43 PM1/17/20
to
Post this over on comp.arch. I generally dislike transactional memory,
but thats just me. There are places where a nice TM can be used in the
writer side of a RCU algorihtm. Readers read, full steam ahead, not even
caring about any transaction. However, the writers use the transactions
when they mutate the data-structure. The readers are totally free, the
writers are not.

Bonita Montero

unread,
Jan 17, 2020, 9:50:06 PM1/17/20
to
>>> Don't pass the lambda by reference to non-`const`, because that
>>> requires the caller to have a lambda /variable/.

>> Why should this be a problem ?

> It imposes needless verbosity and bug vectors on the calling code.

No, that's not bug-prone.

>>> Use RAII (destructor) to ensure that `_xend()` is called even if the
>>> lambda throws an exception.

>> In an transaction you wouldn't do some RAII-ish things anyway but
>> just simple things like some pointer-adjustments in a data-strcuture.
>> Having fully RAII-conformance might grow the transaction working-set
>> too large.

> No, there is no connection between the way you do cleanup (unsafely, or
> as I propose safely) and the transaction working set.

RAII-safeness isn't needed here. There are no resources which might
be allocated in a transaction because a transaction has to be a simple
piece of code whose working-set should fit in the L1-cache.

>>> It seems unlikely that the above could be a callback function with
>>> a signature required by third party code that you don't control.
>>> So, don't use `int` where `bool` (or better, a less conversion-eager
>>> wrapper of `bool`) is more appropriate.
>>  > Don't use a choice operator or conditional expression to compute
>>  > a boolean value when you can directly use a boolean expression.

>> There are three states: transaction successful, transaction aborted but
>> could be restarted and transaction aborted and can't be restarted due to
>> cache-overflow (the l1 couldn't track the whole transaction). How should
>> I do that with a bool which can hold two states ?

> In the same way as your current code which you snipped, which returns
> either 0 or 1.

Ok, but your bool-wrapper is stupid.

Bonita Montero

unread,
Jan 17, 2020, 10:57:58 PM1/17/20
to
>>> Don't pass the lambda by reference to non-`const`, because that
>>> requires the caller to have a lambda /variable/.

>> Why should this be a problem ?

> It imposes needless verbosity and bug vectors on the calling code.

I'm asking myself what a by-reference lambda should be good for.
Having by-copy-captures disables modification of those captures
if you don't jave a mutable lamda anyway. By-reference-captures
can't also be modified, but just the referenced values. So passing
a lambda by const-reference is useless.

Bonita Montero

unread,
Jan 21, 2020, 6:54:00 AM1/21/20
to
> template<typename L>
> inline
> int transaction( L &lambda )
> {
>     unsinged code = _xbegin();
>     if( code == _XBEGIN_STARTED )
>     {
>         lambda();
>         _xend();
>         return 1;
>     }
>     else
>         return code & _XABORT_RETRY ? 0 : -1;
return (code & (_XABORT_RETRY | _XABORT_EXPLICIT)) ==
_XABORT_RETRY ? 0 : -1;
> }

Otherwise aborted transaction will be returned as retryable.

Chris M. Thomasson

unread,
Jan 22, 2020, 7:37:37 PM1/22/20
to
I say this because I have had to deal with several transaction systems
where a simple read of an in-flight transaction would abort! This can
happen in STM, or even in hardware wrt the reservation granule of a
LL/SC. I used RCU for the readers, and let the writers deal with the
damn transactions. seqlock version numbers are helpful as well...

Pavel

unread,
Feb 14, 2020, 11:51:00 PM2/14/20
to
Bonita Montero wrote:
>> template<typename L>
>> inline
>> int transaction( L &lambda )
>> {
>>      unsinged code = _xbegin();
>>      if( code == _XBEGIN_STARTED )
>>      {
>>          lambda();
>>          _xend();
>>          return 1;
>>      }
>>      else
>>          return code & _XABORT_RETRY ? 0 : -1;
>            return (code & (_XABORT_RETRY | _XABORT_EXPLICIT)) == _XABORT_RETRY ?
> 0 : -1;
try

return -(!((code & (_XABORT_RETRY | _XABORT_EXPLICIT)) == _XABORT_RETRY));

to satisfy Alf's dislike of conditional expressions but not int return values :-)

hth but almost kidding..

-Pavel

Bonita Montero

unread,
Feb 15, 2020, 4:03:11 AM2/15/20
to
> return -(!((code & (_XABORT_RETRY | _XABORT_EXPLICIT)) == _XABORT_RETRY));

That's obfuscation.
I like the ternary operator and in contrast to C++ you can do
some nice things like this "++(xyz == CMP ? a : b)" with it.
That's compact and not unreadable like the above.

Bonita Montero

unread,
Feb 15, 2020, 10:59:59 AM2/15/20
to
> That's obfuscation.
> I like the ternary operator and in contrast to *** you can do
C

Pavel

unread,
Feb 15, 2020, 8:58:01 PM2/15/20
to
Bonita Montero wrote:
>> return -(!((code & (_XABORT_RETRY | _XABORT_EXPLICIT)) ==
>> _XABORT_RETRY));
>
> That's obfuscation.
To an extent -- and that was the point (that following some advice on
style could further mess up already messy code).
> I like the ternary operator and in contrast to C++ you can do
> some nice  things like this "++(xyz == CMP ? a : b)" with it.
Now THAT is a) obfuscation and b) irrelevant to your TM idea.
> That's compact and not unreadable like the above.
The comparison is meaningless due to b) above.

Bonita Montero

unread,
Feb 16, 2020, 2:09:36 AM2/16/20
to
>> I like the ternary operator and in contrast to C++ you can do
>> some nice  things like this "++(xyz == CMP ? a : b)" with it.

> Now THAT is a) obfuscation and b) irrelevant to your TM idea.

It's unusual, but readable, so no obfuscation.

Pavel

unread,
Feb 17, 2020, 4:04:24 PM2/17/20
to
It's not really unusual. You "nice thing" pretends to be simple (which
it is not) only because it's example code serving no useful purpose.
Your original code served useful purpose and you immediately found you
had to correct it. The correction made your conditional expression
slightly bulkier and the use of ternary operator (that was originally
reasonable) lost 95% of its initial appeal. It's no longer concise and
not too readable even though it is free of side effects as opposed to
your "nice thing" above. Readable code separates concerns and your "nice
thing" does the opposite.

Bonita Montero

unread,
Feb 18, 2020, 2:10:08 AM2/18/20
to
> It's not really unusual. You "nice thing" pretends to be simple (which
> it is not) only because it's example code serving no useful purpose.
> Your original code served useful purpose and you immediately found you
> had to correct it. The correction made your conditional expression
> slightly bulkier and the use of ternary operator (that was originally
> reasonable) lost 95% of its initial appeal. It's no longer concise and
> not too readable even though it is free of side effects as opposed to
> your "nice thing" above. Readable code separates concerns and your "nice
> thing" does the opposite.

The code I've shown doesn't have a bad redability.
Yours has a bad readabiliy.

Pavel

unread,
Feb 19, 2020, 12:28:49 AM2/19/20
to
I have never said it had bad readability. I said your "nice thing" serving no
purpose was an obfuscation pretending to be simple while not being so. It would
be a bad idea (now I am saying "bad") to use it as an example to do anything useful.

Your original "transaction" code was rather readable although had an unnecessary
"else" clause made it more complex than necessary.

While fixing the bug your worsened the readability from ok to rather poor (again
I am not calling it "bad").

A better readable code for "transaction", after the bug fix and preserving your
preferences for indentation and braces but not new lines and using magic numbers
vs symbolic constants could be, for example:

enum TsxStatusCategory: int {
TSX_ABORTED_DONT_RETRY = -1,
TSX_ABORTED_CAN_RETRY = 0,
TSX_COMMITTED = 1
};

template<typename L>
inline
TsxStatusCategory
doTsxTransaction( L &lambda ) // function name should be a verb [clause]
{
unsigned code = _xbegin(); // unsinged is not unsigned BTW

if( code == _XBEGIN_STARTED )
{
lambda();
_xend();
return TSX_COMMITTED;
} // `else' served no purpose here other than obfuscation

if (code & _XABORT_EXPLICIT)
return TSX_ABORTED_DONT_RETRY;

if (code & _XABORT_RETRY)
return TSX_ABORTED_CAN_RETRY;

return TSX_ABORTED_DONT_RETRY;
}


> Yours has a bad readabiliy.
Yes, it does and as said earlier it is its point.

Bonita Montero

unread,
Feb 19, 2020, 1:28:53 AM2/19/20
to
> I have never said it had bad readability. I said your "nice thing" serving
> no purpose was an obfuscation pretending to be simple while not being so. ...
Whoever finds the contradiction may keep it.

> template<typename L>
> inline
> TsxStatusCategory
> doTsxTransaction( L &lambda ) // function name should be a verb [clause]
> {
> unsigned code = _xbegin(); // unsinged is not unsigned BTW
>
> if( code == _XBEGIN_STARTED )
> {
> lambda();
> _xend();
> return TSX_COMMITTED;
> } // `else' served no purpose here other than obfuscation
>
> if (code & _XABORT_EXPLICIT)
> return TSX_ABORTED_DONT_RETRY;
>
> if (code & _XABORT_RETRY)
> return TSX_ABORTED_CAN_RETRY;
>
> return TSX_ABORTED_DONT_RETRY;
> }
>

That's a matter of taste.

Pavel

unread,
Feb 20, 2020, 12:02:27 AM2/20/20
to
Bonita Montero wrote:
>> I have never said it had bad readability. I said your "nice thing" serving
>> no purpose was an obfuscation pretending to be simple while not being so. ...
> Whoever finds the contradiction may keep it.
Yes, if they inherit obfuscated code they will suffer.
>
>> template<typename L>
>> inline
>> TsxStatusCategory
>> doTsxTransaction( L &lambda ) // function name should be a verb [clause]
>> {
>>      unsigned code = _xbegin(); // unsinged is not unsigned BTW
>>
>>      if( code == _XBEGIN_STARTED )
>>      {
>>          lambda();
>>          _xend();
>>          return TSX_COMMITTED;
>>      } // `else' served no purpose here other than obfuscation
>>
>>      if (code & _XABORT_EXPLICIT)
>>          return TSX_ABORTED_DONT_RETRY;
>>
>>      if (code & _XABORT_RETRY)
>>          return TSX_ABORTED_CAN_RETRY;
>>
>>      return TSX_ABORTED_DONT_RETRY;
>> }
>>
>
> That's a matter of taste.
Rather it is vital matter for any entity that have to maintain their code base.

Bonita Montero

unread,
Feb 20, 2020, 1:47:49 AM2/20/20
to
> Rather it is vital matter for any entity that have to maintain their code base.

The code I've given is simple and readable.

Pavel

unread,
Feb 21, 2020, 1:34:10 AM2/21/20
to
Bonita Montero wrote:
>> Rather it is vital matter for any entity that have to maintain their code base.
>
> The code I've given is simple and readable.
>
Why not if its simplicity and readability are judged by its author right after
it has been written?

To really find out, however, it needs to survive at least a year of
non-occasional use and a couple of change requests ensuing from it, possibly
performed by others acting on similar "tastes".

Bonita Montero

unread,
Feb 21, 2020, 3:32:31 AM2/21/20
to
> Why not if its simplicity and readability are judged by its author right after
> it has been written?
> To really find out, however, it needs to survive at least a year of
> non-occasional use and a couple of change requests ensuing from it, possibly
> performed by others acting on similar "tastes".

You're stupid.
No one has problems to understand such a tiny code-snippet.

Pavel

unread,
Feb 23, 2020, 12:20:59 AM2/23/20
to
Bonita Montero wrote:
>> Why not if its simplicity and readability are judged by its author right after
>> it has been written?
>> To really find out, however, it needs to survive at least a year of
>> non-occasional use and a couple of change requests ensuing from it, possibly
>> performed by others acting on similar "tastes".
>
> You're stupid.
:-)
> No one has problems to understand such a tiny code-snippet.
You posted more than one; which one are you talking about now?

Bonita Montero

unread,
Feb 23, 2020, 4:09:37 AM2/23/20
to
>> No one has problems to understand such a tiny code-snippet.

> You posted more than one; which one are you talking about now?

That's all simple code.

Pavel

unread,
Feb 23, 2020, 6:03:25 PM2/23/20
to
Care to pick one that is most readable in your opinion for me to demonstrate its
readability pitfalls?

Bonita Montero

unread,
Feb 24, 2020, 2:31:28 AM2/24/20
to
> Care to pick one that is most readable in your opinion for me to demonstrate its
> readability pitfalls?

Pople able to manage to handle C++ can read either case good.

Pavel

unread,
Feb 25, 2020, 12:27:01 AM2/25/20
to
Popla manage not handle good.
0 new messages