void CommitChangeToHandle(long stamp)
{
Interlocked.Increment (ref used);
var tmpHandle = handle;
if (tmpHandle != null) {
// First in all case we carry the operation we were called for
if ((stamp & 1) == 1)
tmpHandle.Set ();
else
tmpHandle.Reset ();
/* Then what may happen is that the two suboperations (state change and handle change)
* overlapped with others. In our case it doesn't matter if the two suboperations aren't
* executed together at the same time, the only thing we have to make sure of is that both
* state and handle are synchronized on the last visible state change.
*
* For instance if S is state change and H is handle change, for 3 concurrent operations
* we may have the following serialized timeline: S1 S2 H2 S3 H3 H1
* Which is perfectly fine (all S were converted to H at some stage) but in that case
* we have a mismatch between S and H at the end because the last operations done were
* S3/H1. We thus need to repeat H3 to get to the desired final state.
*/
long currentState;
do {
currentState = state;
if (currentState != stamp && (stamp & 1) != (currentState & 1)) {
if ((currentState & 1) == 1)
tmpHandle.Set ();
else
tmpHandle.Reset ();
}
} while (currentState != state);
}
Interlocked.Decrement (ref used);
}