Boost logo

Boost :

Subject: Re: [boost] [transact] Handling with user exceptions
From: strasser_at_[hidden]
Date: 2010-03-07 12:53:51


Zitat von "vicente.botet" <vicente.botet_at_[hidden]>:
>> assert(tx_a == 0);
>>
>> transaction{
>>
>> tx_a=1;
>>
>> try{
>> transaction{
>> tx_a=2;
>> throw 5;
>> }
>> }catch(int){}
>> assert(tx_a == 1);
>
> if user exceptions commit transaction we have
> assert(tx_a == 2);

even if the inner transaction was rolled back by the user
exception(which is the current behaviour of the macros)? then I'd
consider this a bug.
what other transactional system behaves that way?
SQL databases that support nested transactions(called savepoints in
SQL) don't.

if you want to discuss again if the macros should commit or roll back
on user exceptions that's another discussion, but IF a nested
transaction is rolled back it must not have any effects on the outer
transaction if the outer transaction is committed.

this would make nested transactions unmanageable, since the user would
have to know if a transaction is nested or not.

consider e.g.

/// Provides strong exception guarantee
void f(){
   transaction{
     tx_a=2;
     if(something) throw something;
   }
}

void g(){
   try{
     f();
   }catch(...){
     //ok, that didn't work, try something else. but don't rethrow
     //...
   }
}

void h(){
   transaction{
     tx_other=123;
     g();
   }
}

int main(){
   g(); //ok. in case of an exception, tx_a is unchanged.
   h(); //error. in case of an exception an inconsistent state is committed.
}

> BTW, the default behavior on the Draft C++ Transactional Memory
> documment is to commit the transaction on exception.

I have read it and I find the argument for this to be very weak:

"The TM handler could either commit or abort the current transaction
when an exception is raised. The justification for committing when an
exception occurs is that the memory retains its values as seen at the
time of exception. If the TM handler aborts the TM region, then the
memory may be inconsistent as some of the values may be rolled back.
If an object in C++ is thrown and if this object is undone during an
abort, then the object may be inconsistent when a handler outside the
TM region is examining this object."

this seems to be the entire justification.
imho this is no justification at all, since you can experience exactly
the same thing with regular c++ "strong" exception guarantees.

example:

void f(){
   try{
     this->a=1;
     throw my_exc(this->a);
   }catch(...){
     //strong guarnatee, undo:
     this->a=0;
   }
}

void g(){
   try{
     f();
   }catch(my_exc &e){
     assert(this->a == e.a); //fails!
   }
}

>
>>> The fact that the functions including nested transactions doesn't
>>> satisfy even "The basic guarantee: that the invariants of the
>>> component are preserved, and no resources are leaked." it is not
>>> important as the action has not been commited completly, as only the
>>> root transaction will realize the visible commit.
>>
>> it satisfies the strong guarantee from the viewpoint of the user, i.e.
>> from inside the (still running) root transaction.
>> that the root transaction is not yet published to other threads or to
>> a persistent state doesn't matter, does it?
>
> It matters for me. We don't need this strong guarantee because we
> have yet a resource that allows us to satisfy the strong guarantee
> once the root transaction is commited or aborted.

not sure if understand your point here. the exception guarantee is
given to the (immediate) caller of the function. the caller is not
aware if it is called within a root transactino or not. all it knows
is: if there is an exception, all changes are undone. why does the
root transaction matter at this point?


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk