#[repr(C, align(8))]pub struct AtomicPtr<T> { /* private fields */ }
Expand description
可以在线程之间安全共享的裸指针类型。
此类型与 *mut T
具有相同的内存表示形式。
Note: 此类型仅在支持原子加载和指针存储的平台上可用。 它的大小取决于目标指针的大小。
Implementations§
source§impl<T> AtomicPtr<T>
impl<T> AtomicPtr<T>
const: unstable · sourcepub unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T>
🔬This is a nightly-only experimental API. (atomic_from_ptr
#108652)
pub unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T>
atomic_from_ptr
#108652)从指针创建一个新的 AtomicPtr
。
Examples
#![feature(atomic_from_ptr, pointer_is_aligned)]
use std::sync::atomic::{self, AtomicPtr};
use std::mem::align_of;
// 获取指向分配值的指针
let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut()));
assert!(ptr.is_aligned_to(align_of::<AtomicPtr<u8>>()));
{
// 创建分配值的原子视图
let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
// 使用 `atomic` 进行原子操作,可能与其他线程共享
atomic.store(std::ptr::NonNull::dangling().as_ptr(), atomic::Ordering::Relaxed);
}
// 可以非原子地访问 `ptr` 后面的值,因为对原子的引用在上面的块中结束了它的生命周期
assert!(!unsafe { *ptr }.is_null());
// 释放值
unsafe { drop(Box::from_raw(ptr)) }
RunSafety
ptr
必须与align_of::<AtomicPtr<T>>()
对齐 (请注意,在某些平台上,它可能比align_of::<*mut T>()
大)。- 对于整个生命周
'a
的读取和写入,ptr
必须是 valid。 - 整个生命周
'a
都不能通过非原子操作访问到ptr
后面的值。
sourcepub fn from_mut(v: &mut *mut T) -> &mut Self
🔬This is a nightly-only experimental API. (atomic_from_mut
#76314)
pub fn from_mut(v: &mut *mut T) -> &mut Self
atomic_from_mut
#76314)获得对指针的原子访问。
Examples
#![feature(atomic_from_mut)]
use std::sync::atomic::{AtomicPtr, Ordering};
let mut data = 123;
let mut some_ptr = &mut data as *mut i32;
let a = AtomicPtr::from_mut(&mut some_ptr);
let mut other_data = 456;
a.store(&mut other_data, Ordering::Relaxed);
assert_eq!(unsafe { *some_ptr }, 456);
Runsourcepub fn get_mut_slice(this: &mut [Self]) -> &mut [*mut T]
🔬This is a nightly-only experimental API. (atomic_from_mut
#76314)
pub fn get_mut_slice(this: &mut [Self]) -> &mut [*mut T]
atomic_from_mut
#76314)获得对 &mut [AtomicPtr]
切片的非原子访问。
这是安全的,因为可变引用保证没有其他线程同时访问原子数据。
Examples
#![feature(atomic_from_mut, inline_const)]
use std::ptr::null_mut;
use std::sync::atomic::{AtomicPtr, Ordering};
let mut some_ptrs = [const { AtomicPtr::new(null_mut::<String>()) }; 10];
let view: &mut [*mut String] = AtomicPtr::get_mut_slice(&mut some_ptrs);
assert_eq!(view, [null_mut::<String>(); 10]);
view
.iter_mut()
.enumerate()
.for_each(|(i, ptr)| *ptr = Box::into_raw(Box::new(format!("iteration#{i}"))));
std::thread::scope(|s| {
for ptr in &some_ptrs {
s.spawn(move || {
let ptr = ptr.load(Ordering::Relaxed);
assert!(!ptr.is_null());
let name = unsafe { Box::from_raw(ptr) };
println!("Hello, {name}!");
});
}
});
Runsourcepub fn from_mut_slice(v: &mut [*mut T]) -> &mut [Self]
🔬This is a nightly-only experimental API. (atomic_from_mut
#76314)
pub fn from_mut_slice(v: &mut [*mut T]) -> &mut [Self]
atomic_from_mut
#76314)获得对指针切片的原子访问。
Examples
#![feature(atomic_from_mut)]
use std::ptr::null_mut;
use std::sync::atomic::{AtomicPtr, Ordering};
let mut some_ptrs = [null_mut::<String>(); 10];
let a = &*AtomicPtr::from_mut_slice(&mut some_ptrs);
std::thread::scope(|s| {
for i in 0..a.len() {
s.spawn(move || {
let name = Box::new(format!("thread{i}"));
a[i].store(Box::into_raw(name), Ordering::Relaxed);
});
}
});
for p in some_ptrs {
assert!(!p.is_null());
let name = unsafe { Box::from_raw(p) };
println!("Hello, {name}!");
}
Run1.15.0 (const: unstable) · sourcepub fn into_inner(self) -> *mut T
pub fn into_inner(self) -> *mut T
sourcepub fn store(&self, ptr: *mut T, order: Ordering)
pub fn store(&self, ptr: *mut T, order: Ordering)
将值存储到指针中。
store
需要一个 Ordering
参数,它描述了这个操作的内存顺序。
可能的值为 SeqCst
,Release
和 Relaxed
。
Panics
如果 order
是 Acquire
或 AcqRel
,就会出现 panics。
Examples
use std::sync::atomic::{AtomicPtr, Ordering};
let ptr = &mut 5;
let some_ptr = AtomicPtr::new(ptr);
let other_ptr = &mut 10;
some_ptr.store(other_ptr, Ordering::Relaxed);
Runsourcepub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T
pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T
将一个值存储到指针中,返回前一个值。
swap
需要一个 Ordering
参数,它描述了这个操作的内存顺序。所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持对指针进行原子操作的平台上可用。
Examples
use std::sync::atomic::{AtomicPtr, Ordering};
let ptr = &mut 5;
let some_ptr = AtomicPtr::new(ptr);
let other_ptr = &mut 10;
let value = some_ptr.swap(other_ptr, Ordering::Relaxed);
Runsourcepub fn compare_and_swap(
&self,
current: *mut T,
new: *mut T,
order: Ordering
) -> *mut T
👎Deprecated since 1.50.0: Use compare_exchange
or compare_exchange_weak
instead
pub fn compare_and_swap( &self, current: *mut T, new: *mut T, order: Ordering ) -> *mut T
compare_exchange
or compare_exchange_weak
instead如果当前值与 current
值相同,则将一个值存储到指针中。
返回值始终是前一个值。如果等于 current
,则该值已更新。
compare_and_swap
还带有一个 Ordering
参数,它描述了此操作的内存顺序。
请注意,即使使用 AcqRel
,该操作也可能失败,因此仅执行 Acquire
加载,但没有 Release
语义。
如果发生此操作,则使用 Acquire
使其成为该操作 Relaxed
的存储部分,而使用 Release
使该操作成为存储部分 Relaxed
。
Note: 此方法仅在支持对指针进行原子操作的平台上可用。
迁移到 compare_exchange
和 compare_exchange_weak
compare_and_swap
等效于 compare_exchange
,具有以下内存排序映射:
Original | Success | Failure |
---|---|---|
Relaxed | Relaxed | Relaxed Acquire |
即使比较成功,compare_exchange_weak
也允许虚假失败,这允许编译器在循环中使用比较和交换时生成更好的汇编代码。
Examples
use std::sync::atomic::{AtomicPtr, Ordering};
let ptr = &mut 5;
let some_ptr = AtomicPtr::new(ptr);
let other_ptr = &mut 10;
let value = some_ptr.compare_and_swap(ptr, other_ptr, Ordering::Relaxed);
Run1.10.0 · sourcepub fn compare_exchange(
&self,
current: *mut T,
new: *mut T,
success: Ordering,
failure: Ordering
) -> Result<*mut T, *mut T>
pub fn compare_exchange( &self, current: *mut T, new: *mut T, success: Ordering, failure: Ordering ) -> Result<*mut T, *mut T>
如果当前值与 current
值相同,则将一个值存储到指针中。
返回值是指示是否写入了新值并包含先前值的结果。
成功后,此值保证等于 current
。
compare_exchange
需要两个 Ordering
参数来描述这个操作的内存顺序。
success
描述了在与 current
的比较成功时发生的读取 - 修改 - 写入操作所需的顺序。
failure
描述了比较失败时发生的加载操作所需的排序。
使用 Acquire
作为成功排序,使存储成为操作 Relaxed
的一部分,而使用 Release
,则使装载成功 Relaxed
。
故障顺序只能是 SeqCst
、Acquire
或 Relaxed
。
Note: 此方法仅在支持对指针进行原子操作的平台上可用。
Examples
use std::sync::atomic::{AtomicPtr, Ordering};
let ptr = &mut 5;
let some_ptr = AtomicPtr::new(ptr);
let other_ptr = &mut 10;
let value = some_ptr.compare_exchange(ptr, other_ptr,
Ordering::SeqCst, Ordering::Relaxed);
Run1.10.0 · sourcepub fn compare_exchange_weak(
&self,
current: *mut T,
new: *mut T,
success: Ordering,
failure: Ordering
) -> Result<*mut T, *mut T>
pub fn compare_exchange_weak( &self, current: *mut T, new: *mut T, success: Ordering, failure: Ordering ) -> Result<*mut T, *mut T>
如果当前值与 current
值相同,则将一个值存储到指针中。
与 AtomicPtr::compare_exchange
不同,即使比较成功,也允许该函数错误地失败,这可能导致某些平台上的代码效率更高。
返回值是指示是否写入了新值并包含先前值的结果。
compare_exchange_weak
需要两个 Ordering
参数来描述这个操作的内存顺序。
success
描述了在与 current
的比较成功时发生的读取 - 修改 - 写入操作所需的顺序。
failure
描述了比较失败时发生的加载操作所需的排序。
使用 Acquire
作为成功排序,使存储成为操作 Relaxed
的一部分,而使用 Release
,则使装载成功 Relaxed
。
故障顺序只能是 SeqCst
、Acquire
或 Relaxed
。
Note: 此方法仅在支持对指针进行原子操作的平台上可用。
Examples
use std::sync::atomic::{AtomicPtr, Ordering};
let some_ptr = AtomicPtr::new(&mut 5);
let new = &mut 10;
let mut old = some_ptr.load(Ordering::Relaxed);
loop {
match some_ptr.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
Ok(_) => break,
Err(x) => old = x,
}
}
Run1.53.0 · sourcepub fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F
) -> Result<*mut T, *mut T>where
F: FnMut(*mut T) -> Option<*mut T>,
pub fn fetch_update<F>( &self, set_order: Ordering, fetch_order: Ordering, f: F ) -> Result<*mut T, *mut T>where F: FnMut(*mut T) -> Option<*mut T>,
获取该值,并对其应用一个函数,该函数返回一个可选的新值。如果函数返回 Some(_)
,则返回 Ok(previous_value)
的 Result
,否则返回 Err(previous_value)
。
Note: 如果与此同时从其他线程更改了值,则只要函数返回 Some(_)
,这可能会多次调用该函数,但是该函数仅对存储的值应用一次。
fetch_update
需要两个 Ordering
参数来描述这个操作的内存顺序。
第一个描述了操作最终成功时所需的顺序,第二个描述了负载所需的顺序。
这些分别对应于 AtomicPtr::compare_exchange
的成功和失败顺序。
使用 Acquire
作为成功排序,使存储成为该操作 Relaxed
的一部分,而使用 Release
,则使最终成功加载 Relaxed
。
(failed) 加载顺序只能是 SeqCst
、Acquire
或 Relaxed
。
Note: 此方法仅在支持对指针进行原子操作的平台上可用。
Considerations
这种方法并不神奇; 它不是由硬件提供的。
它是根据 AtomicPtr::compare_exchange_weak
实现的,并且具有相同的缺点。
特别是,这种方法不会绕过 ABA Problem。
Examples
use std::sync::atomic::{AtomicPtr, Ordering};
let ptr: *mut _ = &mut 5;
let some_ptr = AtomicPtr::new(ptr);
let new: *mut _ = &mut 10;
assert_eq!(some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr));
let result = some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
if x == ptr {
Some(new)
} else {
None
}
});
assert_eq!(result, Ok(ptr));
assert_eq!(some_ptr.load(Ordering::SeqCst), new);
Runsourcepub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance_atomic_ptr
#99108)
pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T
strict_provenance_atomic_ptr
#99108)通过添加 val
(以 T
为单位) 偏移指针的地址,返回前一个指针。
这相当于使用 wrapping_add
原子地执行 ptr = ptr.wrapping_add(val);
的等价物。
该方法以 T
为单位进行操作,这意味着它不能用于将指针偏移不是 size_of::<T>()
的倍数的量。
这有时会带来不便,因为您可能希望使用故意未对齐的指针。
在这种情况下,您可以改用 fetch_byte_add
方法。
fetch_ptr_add
接受一个 Ordering
参数,它描述了这个操作的内存顺序。所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持 AtomicPtr
上的原子操作的平台上可用。
Examples
#![feature(strict_provenance_atomic_ptr, strict_provenance)]
use core::sync::atomic::{AtomicPtr, Ordering};
let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
assert_eq!(atom.fetch_ptr_add(1, Ordering::Relaxed).addr(), 0);
// Note: `size_of::<i64>()` 的单位。
assert_eq!(atom.load(Ordering::Relaxed).addr(), 8);
Runsourcepub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance_atomic_ptr
#99108)
pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T
strict_provenance_atomic_ptr
#99108)通过减去 val
(以 T
为单位) 偏移指针的地址,返回前一个指针。
这相当于使用 wrapping_sub
原子地执行 ptr = ptr.wrapping_sub(val);
的等价物。
该方法以 T
为单位进行操作,这意味着它不能用于将指针偏移不是 size_of::<T>()
的倍数的量。
这有时会带来不便,因为您可能希望使用故意未对齐的指针。
在这种情况下,您可以改用 fetch_byte_sub
方法。
fetch_ptr_sub
接受一个 Ordering
参数,它描述了这个操作的内存顺序。所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持 AtomicPtr
上的原子操作的平台上可用。
Examples
#![feature(strict_provenance_atomic_ptr)]
use core::sync::atomic::{AtomicPtr, Ordering};
let array = [1i32, 2i32];
let atom = AtomicPtr::new(array.as_ptr().wrapping_add(1) as *mut _);
assert!(core::ptr::eq(
atom.fetch_ptr_sub(1, Ordering::Relaxed),
&array[1],
));
assert!(core::ptr::eq(atom.load(Ordering::Relaxed), &array[0]));
Runsourcepub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance_atomic_ptr
#99108)
pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T
strict_provenance_atomic_ptr
#99108)通过添加 val
bytes 来偏移指针的地址,返回前一个指针。
这相当于使用 wrapping_byte_add
原子地执行 ptr = ptr.wrapping_byte_add(val)
。
fetch_byte_add
接受一个 Ordering
参数,它描述了这个操作的内存顺序。
所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持 AtomicPtr
上的原子操作的平台上可用。
Examples
#![feature(strict_provenance_atomic_ptr, strict_provenance)]
use core::sync::atomic::{AtomicPtr, Ordering};
let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
assert_eq!(atom.fetch_byte_add(1, Ordering::Relaxed).addr(), 0);
// Note: 以字节为单位,而不是 `size_of::<i64>()`。
assert_eq!(atom.load(Ordering::Relaxed).addr(), 1);
Runsourcepub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance_atomic_ptr
#99108)
pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T
strict_provenance_atomic_ptr
#99108)通过减去 val
bytes 来偏移指针的地址,返回前一个指针。
这相当于使用 wrapping_byte_sub
原子地执行 ptr = ptr.wrapping_byte_sub(val)
。
fetch_byte_sub
接受一个 Ordering
参数,它描述了这个操作的内存顺序。
所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持 AtomicPtr
上的原子操作的平台上可用。
Examples
#![feature(strict_provenance_atomic_ptr, strict_provenance)]
use core::sync::atomic::{AtomicPtr, Ordering};
let atom = AtomicPtr::<i64>::new(core::ptr::invalid_mut(1));
assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1);
assert_eq!(atom.load(Ordering::Relaxed).addr(), 0);
Runsourcepub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance_atomic_ptr
#99108)
pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T
strict_provenance_atomic_ptr
#99108)对当前指针的地址和参数 val
执行按位 “or” 操作,并存储具有当前指针出处的指针和结果地址。
这相当于使用 map_addr
原子地执行 ptr = ptr.map_addr(|a| a | val)
。这可用于标记指针方案以原子地设置标记位。
警告: 此操作返回之前的值。要在不丢失出处的情况下计算存储值,您可以使用 map_addr
。
例如: a.fetch_or(val).map_addr(|a| a | val)
。
fetch_or
需要一个 Ordering
参数,它描述了这个操作的内存顺序。所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持 AtomicPtr
上的原子操作的平台上可用。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 module documentation for ptr
。
Examples
#![feature(strict_provenance_atomic_ptr, strict_provenance)]
use core::sync::atomic::{AtomicPtr, Ordering};
let pointer = &mut 3i64 as *mut i64;
let atom = AtomicPtr::<i64>::new(pointer);
// 标记指针的底部位。
assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 0);
// 提取并取消标记。
let tagged = atom.load(Ordering::Relaxed);
assert_eq!(tagged.addr() & 1, 1);
assert_eq!(tagged.map_addr(|p| p & !1), pointer);
Runsourcepub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance_atomic_ptr
#99108)
pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T
strict_provenance_atomic_ptr
#99108)对当前指针的地址和参数 val
执行按位 “and” 操作,并存储具有当前指针出处的指针和结果地址。
这相当于使用 map_addr
原子地执行 ptr = ptr.map_addr(|a| a & val)
。这可以用于标记指针方案中,以原子方式取消设置标记位。
警告: 此操作返回之前的值。要在不丢失出处的情况下计算存储值,您可以使用 map_addr
。
例如: a.fetch_and(val).map_addr(|a| a & val)
。
fetch_and
需要一个 Ordering
参数,它描述了这个操作的内存顺序。所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持 AtomicPtr
上的原子操作的平台上可用。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 module documentation for ptr
。
Examples
#![feature(strict_provenance_atomic_ptr, strict_provenance)]
use core::sync::atomic::{AtomicPtr, Ordering};
let pointer = &mut 3i64 as *mut i64;
// 标记的指针
let atom = AtomicPtr::<i64>::new(pointer.map_addr(|a| a | 1));
assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 1);
// 取消标记,并提取先前标记的指针。
let untagged = atom.fetch_and(!1, Ordering::Relaxed)
.map_addr(|a| a & !1);
assert_eq!(untagged, pointer);
Runsourcepub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance_atomic_ptr
#99108)
pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T
strict_provenance_atomic_ptr
#99108)对当前指针的地址和参数 val
执行按位 “xor” 操作,并存储具有当前指针出处的指针和结果地址。
这相当于使用 map_addr
原子地执行 ptr = ptr.map_addr(|a| a ^ val)
。这可以用于标记指针方案以原子地切换标记位。
警告: 此操作返回之前的值。要在不丢失出处的情况下计算存储值,您可以使用 map_addr
。
例如: a.fetch_xor(val).map_addr(|a| a ^ val)
。
fetch_xor
需要一个 Ordering
参数,它描述了这个操作的内存顺序。所有排序模式都是可能的。
请注意,使用 Acquire
会使该操作成为存储部分 Relaxed
,而使用 Release
会使装入部分成为 Relaxed
。
Note: 此方法仅在支持 AtomicPtr
上的原子操作的平台上可用。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 module documentation for ptr
。
Examples
#![feature(strict_provenance_atomic_ptr, strict_provenance)]
use core::sync::atomic::{AtomicPtr, Ordering};
let pointer = &mut 3i64 as *mut i64;
let atom = AtomicPtr::<i64>::new(pointer);
// 切换指针上的标记位。
atom.fetch_xor(1, Ordering::Relaxed);
assert_eq!(atom.load(Ordering::Relaxed).addr() & 1, 1);
Run1.70.0 (const: 1.70.0) · sourcepub const fn as_ptr(&self) -> *mut *mut T
pub const fn as_ptr(&self) -> *mut *mut T
返回指向底层指针的可变指针。
在结果整数上进行非原子读取和写入可以是数据竞争。
此方法主要用于 FFI,其中函数签名可能使用 *mut *mut T
而不是 &AtomicPtr<T>
。
从共享引用返回 *mut
指针到此原子是安全的,因为原子类型可与内部可变性一起使用。
原子的所有修改都通过共享的 quot 更改值,并且只要它们使用原子操作就可以安全地进行更改。
对返回的裸指针的任何使用都需要一个 unsafe
块,并且仍然必须遵守相同的限制:对其进行的操作必须是原子的。