SO не всегда токсичен
Mar. 14th, 2021 01:10 pmhttps://stackoverflow.com/questions/66617330/why-there-is-a-flickering-of-old-image-if-i-change-vew-port-for-canvas-before-ca
pub struct Screen{
bytes: Vec<std::sync::atomic::AtomicU32>,
width: u32,
height: u32
}
impl Screen {
pub fn copy_to_buffer<T>(&self, target: &mut [T]) -> Result<(), &'static str>
where T: bytemuck::Pod{
if self.bytes.len() != target.len(){
return Err("Size of target should be the same as source.")
}
let target_u32: &mut [u32] = bytemuck::cast_slice_mut(target);
for idx in 0..self.bytes.len(){
target_u32[idx] = self.bytes[idx].load(Relaxed);
}
Ok(())
}
}
Так сказать, "а что, так можно было"?
Если мне сейчас удастся малой кровью сделать его мутабельным (я верю в тебя, атомик) и пропихнуть между тредами, то это же просто праздник какой-то. У меня будет шаренная между тредами память с Relaxed моделью, в которой в одном треде я мирно делаю copy_to_buffer
Что мне нужен атомик, меня уговорили на форуме, пригрозив, что без атомика компилятор может просто соптимизировать повторный доступ к непоменявшимся (с его точки зрения) данным.
Бенчмарк показал, что запись в атомик в Relaxed занимает столько же времени, как и в обычный u32.
Я пока не до конца уверен, что я в правильном направлени иду, но вот какая у меня идея:
Мне нужно в новый тред отдавать ссылки только со 'static, а я хочу туда отдать (из метода структуры) ссылку на кусок "себя". Что, очевидно, нарушает 'static, потому что если "себя" сделают drop() по выходу из блока/функции, будет danging pointer, а весь раст строился вокруг того, чтобы такого не было. И нужно именно так сделать.
Задача: сохранить инвариант. Т.е. сделать так, чтобы при drop() себя, отданная ранее в соседний тред ссылка была бы жива. Это традиционная задача AI tetris (https://www.youtube.com/embed/xOCurBYI_gY?start=910&feature=oembed&enablejsapi=1), и она прекрасно решается с помощью bottom type.
impl Drop for Screen{
fn drop(&mut self){
if let Some(..) = self.thread {
println!("Attempt to drop Screen. Looping forever.");
loop{}
}
}
}
Такой подход гарантирует: а) что ссылка жива до конца программы. б) что структуру можно создавать с не 'static lifetime, потому что есть drop().
В самой программе нужно, конечно, выходить не через return:
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => std::process::exit(0),
_ => {}
}
Это была простая часть. А теперь сложная - как бы мне сделать mut slice и slice на один и тот же набор данных, чтобы мне за это не особо много влетело?
stay tuned.