#rust
Вопрос:
Поэтому я экспериментирую с некоторыми алгоритмами без блокировки и алгоритмами без ожидания в rust. Я обнаружил, что этот AtomicPtr
класс здесь весьма полезен, поскольку он позволяет выполнять такие операции, как cmpexchange или обмен и т.д. Значениями указателей для реализаций структур данных без блокировки. Тем не менее, я прочитал кое-что потенциально касающееся правил Rust о сглаживании указателей :
Нарушение правил сглаживания указателя. amp;mut T и amp;T следуют модели ноалии LLVM, за исключением случаев, когда amp;T содержит незащищенную ячейку. Изменение неизменяемых данных. Все данные внутри элемента const неизменяемы. Кроме того, все данные, полученные с помощью общей ссылки или данных, принадлежащих неизменяемой привязке, являются неизменными, если только эти данные не содержатся в незащищенной ячейке.
Более того, раздел LLVM, на который они ссылаются, также звучит относительно
Это указывает на то, что места в памяти, доступ к которым осуществляется с помощью значений указателя, основанных на аргументе или возвращаемом значении, также недоступны во время выполнения функции с помощью значений указателя, не основанных на аргументе или возвращаемом значении. Эта гарантия распространяется только на места в памяти, которые каким-либо образом изменяются во время выполнения функции.
Из этого не совсем ясно, как атомику можно считать определенным поведением, поскольку атомарная операция изменяет содержимое данных, на которые указывает указатель. Документы Rust и LLVM перечисляют атомику как исключение из этого правила.
Таким образом, я хотел знать, будет ли следующий код считаться неопределенным поведением в Rust:
struct Point {
x:AtomicUsize,
y:AtomicUsize
}
impl Point {
fn new_ptr() -> *mut Point {
Box::into_raw(Box::new(Point{x:AtomicUsize::new(0), y:AtomicUsize::new(0)}))
}
}
fn main() {
let point = Point::new_ptr();
let cont = AtomicPtr::new(point);
let handle = thread::spawn(move || {
let r = unsafe { cont.load(Ordering::SeqCst).as_ref().unwrap() };
for _ in 0..10000 {
r.x.fetch_add(1, Ordering::SeqCst);
}
});
unsafe { point.as_ref().unwrap().x.fetch_add(1, Ordering::SeqCst); }
handle.join().unwrap();
unsafe {
drop(Box::from_raw(point));
}
}
Он компилируется и выполняется, как и ожидалось, с небольшими изменениями. Но не уверен, является ли то, что я делаю, неопределенным или нет. Я хочу убедиться, что это разрешенное поведение не будет ограничено или изменено в будущем.
Комментарии:
1. Ваш код не нарушает правила псевдонимов, потому что вы создаете общие ссылки только из указателей. Таким образом, ваш код эквивалентен этому безопасному коду . Атомика «нарушает правила» за счет внутренней изменяемости, используя
UnsafeCell
внутреннее, что упоминается как исключение в первом процитированном абзаце.2. Я предполагаю, что вы пытаетесь бороться с моделью сломанной ржавчины (
static
требование к сроку службы). Код сmem::transmute
может быть лучше.3. @ensc Нарушает ли правило Rust, изложенное выше, в отношении псевдонимов ? Я знаю правило о ссылках между потоками, но еще более любопытно, считается ли преобразованная ссылка более чем одним псевдонимом или нет.