Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decrement atomic counter - but <only> under a condition

I want to realize something on this lines:

        inline void DecrementPendingWorkItems()
        {
            if(this->pendingWorkItems != 0) //make sure we don't underflow and get a very high number
            {
                ::InterlockedDecrement(&this->pendingWorkItems);
            }
        }

How can I do this so that both operations are atomic as a block, without using locks ?

like image 214
Ghita Avatar asked Jan 26 '26 14:01

Ghita


2 Answers

You can just check the result of InterlockedDecrement() and if it happens to be negative (or <= 0 if that's more desirable) undo the decrement by calling InterlockedIncrement(). In otherwise proper code that should be just fine.

like image 129
Alexey Frunze Avatar answered Jan 29 '26 06:01

Alexey Frunze


The simplest solution is just to use a mutex around the entire section (and for all other accesses to this->pendingWorkItems). If for some reason this isn't acceptable, then you'll probably need compare and exchange:

void decrementPendingWorkItems()
{
    int count = std::atomic_load( &pendingWorkItems );
    while ( count != 0
            && ! std::atomic_compare_exchange_weak( 
                    &pendingWorkItems, &count, count - 1 ) ) {
    }
}

(This supposes that pendingWorkItems has type std::atomic_int.)

like image 35
James Kanze Avatar answered Jan 29 '26 04:01

James Kanze