Reputation: 8530
Given the following simple lock-free linear allocation algorithm I made:
bool allocate(size_type size, size_type& offset)
{
size_type pos;
size_type new_pos;
pos = m_pos.load(std::memory_order_acquire);
do
{
new_pos = pos + size;
if (new_pos > m_end)
return false;
}
while (!m_pos.compare_exchange_weak(pos, new_pos, std::memory_order_acq_rel, std::memory_order_acquire));
offset = pos;
return true;
}
I would like to improve it further to be wait-free on the fast path, discarding the CAS-loop completely and preferably using fetch_add
, however I'm not sure how to handle the case when the allocation fails because the the requested size is greater than the available size - when this is detected the fetch_add
is already incremented the position which is now over the valid range which may be simultaneously loaded by other threads, which would increment it further and have the false illusion that there is no space for the allocation. Some kind of spin-wait loop is still required in this path, however I can't come up with a valid solution.
Any idea?
Upvotes: 2
Views: 375
Reputation: 2556
Let's say we have 256MB of space. The first thread tries to allocate 257MB of space, which obviously returns false.
To handle that, you can store two ints:
then:
// first attempt, atomic load current_pos
// to early exit when the allocation would certainly fail,
// which will reduce wasting memory
current := atomic_load(current_pos)
if ( current + required > capacity) { return error }
// second attempt, atomic fetch_and_add current_pos
// it can still fail, since other threads may advanced current_pos
// in the background since the previous load
current := fetch_and_add(current_pos, required)
if ( current + required > capacity) {return error}
This is wait free, and can handle OOM errors.
Upvotes: 1