I hadn’t seen this concept, and wanted to let others know, and ask how it contrasts to Julia, but to answer my own question:
In a multithreaded computing environment, hazard pointers are one approach to solving the problems posed by dynamic memory management of the nodes in a lock-free data structure. These problems generally arise only in environments that don’t have automatic garbage collection.
So Julia doesn’t need it, nor likely much of the new support in C++20, 23 and coming in 26. But you CAN program in Julia at a lower level, avoiding the GC, and then you might…
One way to deal with concurrency is to only use immutables, e.g. ruling out the default Dict. but recent HAMT implementations helps with that. With no mutables (that also includes the default mutable arrays/vectors, but not default strings) there are NO bug or security issues regarding concurrency.
Running Julia as default, i.e. not with -t auto, or some number other than 1, avoids some bug issues. But concurrency is frequently wanted for speed.
Then you need to lock and/or use atomic access. Types up to U/Int64 allow atomic access with the default alignment, but it’s not clear to me with e.g. UInt128. @Elrod On all modern cached CPUs, I believe no problem, assuming the type doesn’t split across cache lines, but it doesn’t have 128-bit alignment, only 64-bit. I think that decision for Julia was done to not waste space, emulating other languages such as C++. It’s been a little hard for me to dig into if it’s atomic in Julia or other languages, as it depends on the CPU more than the lang spec. ChatGPT has npot been very helpful, basically “it depends” on the CPU. But I want a guarantee (for all (modern) CPU, and not just x86. Though even just knowing for most common, e.g. x86 and ARM would be nice.
Is the rule that you are unsafe for larger types/structs? Without explicit locking? I want to know for without, or “lock-free”. Note, I think BigFloat/BigInt are actually safe, since hidden behind a (no large-than) 64-bit pointer.
E.g. a rational of Int64, the default Rational is likely not safe. I’m asking because I’m implementing a new one, SIMD rational…
To motivate the use of hazard pointers, let us consider a problem: we want to implement a concurrent key-value map that satisfy the Write-Rarely-Read-Many (WRRM) property. WRRM maps are commonly used as caches, and in use cases such as a lookup table for currency to exchange rates where the map is looked up many times but only updated at a comparatively much slower rate.
In other words, we want to implement a multithreaded-access map interface, using a single threaded map object such as
std::map
.
1.4 Rationale for inclusion in C++26
This proposal is based on the experience gained from hazard pointer implementation in the Facebook Folly open-source library (since 2016) and its heavy use in production (since 2017)
Why in std:
https://www.reddit.com/r/cpp/comments/sywjf3/p2530_hazard_pointers_belong_in_the_standard/
I’m nominally a coauthor, although just because of my work on the original hazard pointer paper. The paper gives a pitch for “sooner rather than later”, but doesn’t really emphasize the answer to “why include it” […]
It was a bit too much for me to start a 5 hour video “Implementing Hazard Pointers in Rust” on a language I don’t (currently) use:
“Brief” introduction: