Files
hashmap_concurrent/README.md
2026-02-26 16:41:08 +01:00

2.0 KiB

HashMapConcurrent

A thread-safe, fixed-capacity, open-addressing hash map for Zig.

This implementation combines Robin Hood hashing (to minimize probe lengths) with Sequence Locking (to provide wait-free-like read performance) and Shard-Level Locking for writers. Deletions use Backward-Shift to maintain table compactness without the performance degradation of tombstones.

Quick Start

const std = @import("std");
const HashMap = @import("hashmap_concurrent.zig").AutoHashMapConcurrent;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    // capacity must be a power of two.
    // num_shards balances writer contention vs reader retry probability.
    var map = try HashMap(u64, u64).init(allocator, 1024, 64);
    defer map.deinit(allocator);

    map.put(42, 1337);
    const val = map.get(42);
    std.debug.print("Value: {d}\n", .{val});
}

Iteration

There are two ways to iterate over entries, depending on your consistency requirements:

lockingIterator(): Uses Lock Coupling to prevent elements from being missed or seen twice if they are moved across shard boundaries during iteration. Due to the locking you must call it.deinit() if you break or return from the loop early to release the held shard lock.

approximateIterator(): Optimistic and approximate because it just uses Sequence Locks. It may miss entries or see the same entry twice if concurrent writers move elements. It's Lock-free and safe to use on const references. Safe to break early without cleanup.

Usage & Safety

For a detailed explanation of the concurrency model, deadlock safety, and memory reclamation, please refer to the documentation at the top of hashmap_concurrent.zig.

License

BSD 3-Clause. See hashmap_concurrent.zig and LICENSE for the full text.

Benchmark Results

Done with 100 million iterations on a quiet AMD Ryzen AI 5 340.

Throughput Results

Speedup Results