logoalt Hacker News

tyushk • today at 3:14 AM • 3 replies • view on HN

The single stack allocator seems to be an arena by other terms, but the double headed version is pretty neat.

Is the final pattern described actually safe for multi-threaded use? Something like the stack has exactly 1 byte left, T1 allocates the dynamic end with 1 byte (dynamic object just happened to be 1 byte, say) and T2 allocates the fixed size end with 1 byte. Wouldn't they end up overlapping in that case?


Replies

singron • today at 4:53 AM

I think it's OK to increment/decrement the ends past each other as long as you detect that and fail the allocation for at least one end.

It's a little tricky with memory orders since you are synchronizing on two different locations. The simplest thing is to make all atomic accesses seqcst, but I think a single fence(seqcst) before checking overlap is sufficient in this case and will use fewer synchronizing instructions.

The overflow checks are also tricky. We want to make sure that if an allocation fails, subsequent allocations also fail (even on other threads), and overflow might allow them to think they succeeded by incrementing again back into a valid range. This means you generally can't use fetch_add in a thread-safe bump allocator and instead need to use a CAS loop where you detect overflow before writing.

Since you are doing a CAS loop anyway and always accessing both variables, it might actually be faster to combine both variables, especially if you typically allocate from both at the same time. E.g. if you pack two offsets into a 64-bit CAS word, you can still address 4GB, and you can get even more by aligning allocations. You also don't have to worry about seqcst.

hnav • today at 3:49 AM

It could be if you packed both tos variables into a single atomic and the compare and swapped the combined value.

saagarjha • today at 3:47 AM

You’d need synchronization in the allocator but typically this is pretty cheap (often these allocations come from one thread and may get handed out to multiple consumers who work on them in parallel).