10 stable releases

2.0.0 Feb 24, 2025
1.4.1 Feb 9, 2024
1.3.0 Mar 13, 2023
1.2.1 Nov 5, 2022
1.0.0 Nov 5, 2020

#128 in Concurrency

Download history 6/week @ 2024-11-16 9/week @ 2024-11-23 5/week @ 2024-11-30 33/week @ 2024-12-07 6/week @ 2024-12-14 32/week @ 2024-12-28 62/week @ 2025-01-04 71/week @ 2025-01-11 8/week @ 2025-01-18 10/week @ 2025-01-25 195/week @ 2025-02-01 155/week @ 2025-02-08 181/week @ 2025-02-15 259/week @ 2025-02-22 135/week @ 2025-03-01

803 downloads per month
Used in supergit

GPL-3.0-or-later

17KB
275 lines

AtomPtr

A safe wrapper around std::sync::atomic::AtomPtr, improving its ergonomics, enforcing safety and indirection checks, and bringing some extra tricks for more granular concurrent datastructure design.

Quickstart

use atomptr::AtomPtr;

// Create some complex data and create an AtomPtr around it
let my_data = String::from("std::sync::atomic::AtomicPtr");
let p = AtomPtr::new(my_data);

// A 'Ref' is a snapshot of the inner 'AtomPtr' value.  Even if the
// unner value were to change, a Ref keeps an old snapshot alive until
// the last instance of it is dropped.
let p_ref = p.get_ref();

// 'AtomPtr' is copy-on-write, so we perform 'uwu_clone' (or 'uwu_copy') to
// get full ownership of the data referenced by the snapshot.  We can then
// freely make changes to the data.
let my_data2 = p_ref
	.uwu_clone()
	.split("::")
    .filter_map(|segmnt| match segmnt {
        "std" => Some("atomptr"),
        "sync" => Some("AtomPtr"),
        _ => None,
    })
    .collect::<Vec<_>>()
    .join("::");

// Use either `swap()` or `compare_exchange()` to replace the data
let _ = p.compare_exchange(p_ref, my_data2.clone()).unwrap_ref();

let p_ref = p.get_ref();
assert_eq!(p_ref.count(), 2);
assert_eq!(p_ref.uwu_clone(), my_data2);

Migrating from 1.x versions

Due to a few API changes the version was suddenly from 1.4.x to 2.0.0, not giving any deprecation time for the newly removed items. To allow a smoother upgrade path for existing consumers when upgrading can enable the stable feature, which will opt-out of the code-breaking changes of the API, giving them time to port over their usage.

Furthermore deprecations have been made with this bump. Warnings turn to errors in version 2.1.0, and the stable feature is removed in version 2.2.0

This crate wraps a given T into an Arc<T>, then stores an "owned reference" into the AtomicPtr.

A safe wrapper around atomic pointers to build datastructures and lock-free algorithms on top of. Only uses std as a dependency.

The standard library contains an AtomicPtr type, which by itself is very unergonomic to use, because it deals with raw pointers. It is very easy to misuse this API and get memory leaks or double-free.

This library makes some assumptions about how you would like to use your data. Furthermore, it is dangerous to use raw pointers without some other memory management strategy. This crate uses Arc<T> to handle reference lifetime management. Data in an AtomPtr<T> is also always heap allocated.

Following is a simple example.

use atomptr::AtomPtr;

struct MyData { name: String }
let data = MyData { name: "Kookie".into() };

let a = AtomPtr::new(data);
println!("Name is: {}", a.get_ref().name);

let old_ref = a.swap(MyData { name: "Bob".into() });
println!("Name now is: {}, was {}", a.get_ref().name, old_ref.name);

Because all data is wrapped by Arc<T> internally, returning a reference of the underlying data doesn't mean it is removed from the pointer itself, or de-allocated after Ref<T> goes out of scope. Another thread can of course swap the data contained in the pointer, which is why compare_exchange requires a previously held data reference.

No runtime deps

Features