PerThreadBumpPtrAllocator allows separating allocations by thread id.
That makes allocations race free. It is possible because
ThreadPoolExecutor class creates threads, keeps them until
the destructor of ThreadPoolExecutor is called, and assigns ids
to the threads. Thus PerThreadBumpPtrAllocator should be used with only
threads created by ThreadPoolExecutor. This allocator is useful when
thread safe BumpPtrAllocator is needed.
Details
- Reviewers
MaskRay dblaikie dexonsmith steven_wu
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
It's nice how simple this is!
Thus ThreadPoolAllocator should be used with only
threads created by ThreadPoolExecutor.
I hadn't thought deeply about this limitation previously...
This seems fine for many APIs. But, I don't think the CAS could use this, since clients might share a CAS between multiple threads NOT owned by ThreadPoolAllocator. For the CAS, probably we need to stick with https://reviews.llvm.org/D133713 for now (probably eventually use a lock-free ConcurrentBumpPtrAllocator instead).
I agree that this probably doesn't work for CAS since the use of CAS is not bounded to any context like a ThreadPoolExecutor, for example, it is currently a legal use case to have multiple thread pool to insert into CAS at the same time. It is not feasible to put such a restriction on CAS since CAS should be safe to read/write concurrently from different process.
For this PoolAllocator, it might be a good idea to require it to be initialized with an instance of ThreadPoolExecutor and maybe add a method for Thread to get the context of its Executor so you can double check the allocator is used in the correct Exectuor when assertion is on.
I see, My first intention was to implement some similar solution. But it requires an additional refactoring(f.e. ThreadPoolExecutor is not currently visible). This patch is simple working implementation allowing to check the idea.
I was thinking about something like that:
class ThreadPoolAllocator { void *Allocate(size_t size, size_t alignment); }; class ThreadPool { std::unique_ptr<ThreadPoolAllocator> getAllocator (); }; class ThreadPoolExecutor { std::unique_ptr<ThreadPoolAllocator> getAllocator (); };