View source code
Display the source code in std/experimental/allocator/building_blocks/bitmapped_block.d from which this page was generated on github.
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone.

Struct std.experimental.allocator.building_blocks.bitmapped_block.SharedBitmappedBlock

The threadsafe version of the BitmappedBlock. The semantics of the SharedBitmappedBlock are identical to the regular BitmappedBlock.

struct SharedBitmappedBlock(ulong theBlockSize, uint theAlignment = platformAlignment, ParentAllocator, Flag!("multiblock") f = Yes.multiblock) ;

Constructors

NameDescription
this (data) Constructs a block allocator given a hunk of memory, or a desired capacity in bytes.
  • If ParentAllocator is NullAllocator, only the constructor taking data is defined and the user is responsible for freeing data if desired.
  • Otherwise, both constructors are defined. The data-based constructor assumes memory has been allocated with the parent allocator. The capacity-based constructor uses ParentAllocator to allocate an appropriate contiguous hunk of memory. Regardless of the constructor used, the destructor releases the memory by using ParentAllocator.deallocate.

Fields

NameTypeDescription
parent ParentAllocatorThe parent allocator. Depending on whether ParentAllocator holds state or not, this is a member variable or an alias for ParentAllocator.instance.

Methods

NameDescription
alignedAllocate (n, a) Allocates a block with specified alignment a. The alignment must be a power of 2. If a <= alignment, function forwards to allocate. Otherwise, it attempts to overallocate and then adjust the result for proper alignment. In the worst case the slack memory is around two blocks.
alignedReallocate (b, newSize, a) Reallocates a block previously allocated with alignedAllocate. Contractions do not occur in place.
allocate (s) Allocates s bytes of memory and returns it, or null if memory could not be allocated.
allocateAll () If the SharedBitmappedBlock object is empty (has no active allocation), allocates all memory within and returns a slice to it. Otherwise, returns null (i.e. no attempt is made to allocate the largest available block).
allocateFresh (s) Allocates s bytes of memory and returns it, or null if memory could not be allocated. allocateFresh behaves just like allocate, the only difference being that this always returns unused(fresh) memory. Although there may still be available space in the SharedBitmappedBlock, allocateFresh could still return null, because all the available blocks have been previously deallocated.
deallocate (b) Deallocates the given buffer b, by atomically setting the corresponding bit to 0. b must be valid, and cannot contain multiple adjacent blocks.
deallocateAll () Forcibly deallocates all memory allocated by this allocator, making it available for further allocations. Does not return memory to ParentAllocator.
empty () Returns Ternary.yes if no memory is currently allocated with this allocator, otherwise Ternary.no. This method never returns Ternary.unknown.
expand (b, delta) Expands in place a buffer previously allocated by SharedBitmappedBlock. Expansion fails if the new length exceeds the block size.
goodAllocSize (n) Returns the actual bytes allocated when n bytes are requested, i.e. n.roundUpToMultipleOf(blockSize).
owns (b) Returns Ternary.yes if b belongs to the SharedBitmappedBlock object, Ternary.no otherwise. Never returns Ternary.unkown. (This method is somewhat tolerant in that accepts an interior slice.)
reallocate (b, newSize) Reallocates a previously-allocated block. Contractions occur in place.

Aliases

NameDescription
alignment The alignment offered is user-configurable statically through parameter theAlignment, defaulted to platformAlignment.
blockSize If blockSize == chooseAtRuntime, SharedBitmappedBlock offers a read/write property blockSize. It must be set before any use of the allocator. Otherwise (i.e. theBlockSize is a legit constant), blockSize is an alias for theBlockSize. Whether constant or variable, must also be a multiple of alignment. This constraint is asserted statically and dynamically.

Parameters

NameDescription
theBlockSize the length of a block, which must be a multiple of theAlignment
theAlignment alignment of each block
ParentAllocator allocator from which the BitmappedBlock will draw memory. If set to NullAllocator, the storage must be passed via the constructor
f Yes.multiblock to support allocations spanning across multiple blocks and No.multiblock to support single block allocations. Although limited by single block allocations, No.multiblock will generally provide higher performance.

Example

import std.experimental.allocator.mallocator : Mallocator;
import std.experimental.allocator.common : platformAlignment;
import std.typecons : Flag, Yes, No;

// Create 'numThreads' threads, each allocating in parallel a chunk of memory
static void testAlloc(Allocator)(ref Allocator a, size_t allocSize)
{
    import core.thread : ThreadGroup;
    import std.algorithm.sorting : sort;
    import core.internal.spinlock : SpinLock;

    SpinLock lock = SpinLock(SpinLock.Contention.brief);
    enum numThreads = 10;
    void[][numThreads] buf;
    size_t count = 0;

    // Each threads allocates 'allocSize'
    void fun()
    {
        void[] b = a.allocate(allocSize);
        writeln(b.length); // allocSize

        lock.lock();
        scope(exit) lock.unlock();

        buf[count] = b;
        count++;
    }

    auto tg = new ThreadGroup;
    foreach (i; 0 .. numThreads)
    {
        tg.create(&fun);
    }
    tg.joinAll();

    // Sorting the allocations made by each thread, we expect the buffers to be
    // adjacent inside the SharedBitmappedBlock
    sort!((a, b) => a.ptr < b.ptr)(buf[0 .. numThreads]);
    foreach (i; 0 .. numThreads - 1)
    {
        assert(buf[i].ptr + a.goodAllocSize(buf[i].length) <= buf[i + 1].ptr);
    }

    // Deallocate everything
    foreach (i; 0 .. numThreads)
    {
        assert(a.deallocate(buf[i]));
    }
}

enum blockSize = 64;
auto alloc1 = SharedBitmappedBlock!(blockSize, platformAlignment, Mallocator, Yes.multiblock)(1024 * 1024);
auto alloc2 = SharedBitmappedBlock!(blockSize, platformAlignment, Mallocator, No.multiblock)(1024 * 1024);
testAlloc(alloc1, 2 * blockSize);
testAlloc(alloc2, blockSize);

Authors

License