LINUX.ORG.RU

Rust, sdl3, обработка событий в треде

 ,


0

4

Задача сделать так, чтобы все события клавиатуры обрабатывались в своём цикле в отдельном треде. Сделать без треда у меня получилось, когда добавляю тред начинается какой то ад с владением над переменными и полная консоль ошибок.

Вот код:

Cargo.toml

[package]
name = "test"
version = "0.0.1-alpha.0"
edition = "2018"

[dependencies]
sdl3 = { version = "0.14.26", features = ["build-from-source"]}
gl = "0.14.0"

[dev-dependencies]

main.rs

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
  let mut win = test::win::init("Test", 1920, 1080);

  gl::load_with(|s| win.video_subsystem.gl_get_proc_address(s).unwrap() as *const _);

  let offset_x = Arc::new(Mutex::new(0));

  let a_clone_offset_x = Arc::clone(&offset_x);
  win.key_handlers.insert("A".to_string(), Box::new(move || {
    *a_clone_offset_x.lock().unwrap() -= 1;
    println!("{:?}", a_clone_offset_x);
  }));
  
  let d_clone_offset_x = Arc::clone(&offset_x);
  win.key_handlers.insert("D".to_string(), Box::new(move || {
    *d_clone_offset_x.lock().unwrap() += 1;
    println!("{:?}", d_clone_offset_x);
  }));

  // thread::spawn(move || {
    win.handle_events();
  // });

  loop {};
}

win.rs

use sdl3::{Sdl, VideoSubsystem, EventPump};
use sdl3::video::{GLProfile, GLContext, Window};
use std::collections::HashMap;

pub struct Win {
  pub sdl_context: Sdl, 
  pub video_subsystem: VideoSubsystem,
  pub window: Window,
  pub gl_context: GLContext, 
  pub event_pump: EventPump,
  pub key_handlers: HashMap<String, Box<dyn Fn() -> () >>,
}

pub fn init(title: &str, width: u32, height: u32) -> Win {
  let sdl_context = sdl3::init().unwrap();
  let video_subsystem = sdl_context.video().unwrap();
  let gl_attr = video_subsystem.gl_attr();

  gl_attr.set_context_profile(GLProfile::Core);
  gl_attr.set_context_flags().debug().set();
  gl_attr.set_context_version(3, 3);
  gl_attr.set_multisample_buffers(1);
  gl_attr.set_multisample_samples(4);

  let window = video_subsystem.window(title, width, height)
    .position_centered()
    .resizable()
    // .maximized()
    // .fullscreen()
    .opengl()
    .build()
    .unwrap();

  let gl_context = window.gl_create_context().unwrap();
  let event_pump = sdl_context.event_pump().unwrap();
  let key_handlers = HashMap::new();

  Win {sdl_context, video_subsystem, window, gl_context, event_pump, key_handlers}
}


impl Win {
  pub fn handle_events(&mut self) {
    let event_pump = &mut self.event_pump;

    loop {
      use sdl3::event::Event;
      use sdl3::event::Event::KeyDown;
      use sdl3::keyboard::Keycode::*;
      
      let event = event_pump.wait_event();
      
      // println!("{:?}", event);

      match event {
        Event::Quit {..} => std::process::exit(123),
        KeyDown { keycode: Some(A), .. } => self.key_handlers["A"](),
        KeyDown { keycode: Some(D), .. } => self.key_handlers["D"](),
        _ => {}
      }
    }
  }
}

Если в main.rs добавить тред вокруг win.handle_events(); получаю вот это

error[E0277]: `*mut sdl3_sys::generated::video::SDL_GLContextState` cannot be sent between threads safely
   --> src/main.rs:23:17
    |
23  |     thread::spawn(move || {
    |     ------------- ^------
    |     |             |
    |  ___|_____________within this `{closure@src/main.rs:23:17: 23:24}`
    | |   |
    | |   required by a bound introduced by this call
24  | |     win.handle_events();
25  | |   });
    | |___^ `*mut sdl3_sys::generated::video::SDL_GLContextState` cannot be sent between threads safely
    |
    = help: within `{closure@src/main.rs:23:17: 23:24}`, the trait `Send` is not implemented for `*mut sdl3_sys::generated::video::SDL_GLContextState`
note: required because it appears within the type `sdl3::video::GLContext`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:519:12
    |
519 | pub struct GLContext {
    |            ^^^^^^^^^
note: required because it appears within the type `Win`
   --> /home/archer/Work/Test/src/win.rs:5:12
    |
5   | pub struct Win {
    |            ^^^
note: required because it's used within this closure
   --> src/main.rs:23:17
    |
23  |   thread::spawn(move || {
    |                 ^^^^^^^
note: required by a bound in `spawn`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1

error[E0277]: `*mut ()` cannot be sent between threads safely
   --> src/main.rs:23:17
    |
23  |     thread::spawn(move || {
    |     ------------- ^------
    |     |             |
    |  ___|_____________within this `{closure@src/main.rs:23:17: 23:24}`
    | |   |
    | |   required by a bound introduced by this call
24  | |     win.handle_events();
25  | |   });
    | |___^ `*mut ()` cannot be sent between threads safely
    |
    = help: within `{closure@src/main.rs:23:17: 23:24}`, the trait `Send` is not implemented for `*mut ()`
note: required because it appears within the type `PhantomData<*mut ()>`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/core/src/marker.rs:753:12
note: required because it appears within the type `sdl3::sdl::VideoSubsystem`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/sdl.rs:308:12
    |
308 | subsystem!(VideoSubsystem, SDL_INIT_VIDEO, VIDEO_COUNT, nosync);
    |            ^^^^^^^^^^^^^^
note: required because it appears within the type `Win`
   --> /home/archer/Work/Test/src/win.rs:5:12
    |
5   | pub struct Win {
    |            ^^^
note: required because it's used within this closure
   --> src/main.rs:23:17
    |
23  |   thread::spawn(move || {
    |                 ^^^^^^^
note: required by a bound in `spawn`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1

error[E0277]: `*mut sdl3_sys::generated::video::SDL_Window` cannot be shared between threads safely
   --> src/main.rs:23:17
    |
23  |     thread::spawn(move || {
    |  ___-------------_^
    | |   |
    | |   required by a bound introduced by this call
24  | |     win.handle_events();
25  | |   });
    | |___^ `*mut sdl3_sys::generated::video::SDL_Window` cannot be shared between threads safely
    |
    = help: within `sdl3::video::WindowContext`, the trait `Sync` is not implemented for `*mut sdl3_sys::generated::video::SDL_Window`
note: required because it appears within the type `sdl3::video::WindowContext`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:544:12
    |
544 | pub struct WindowContext {
    |            ^^^^^^^^^^^^^
    = note: required for `Arc<sdl3::video::WindowContext>` to implement `Send`
note: required because it appears within the type `sdl3::video::Window`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:683:12
    |
683 | pub struct Window {
    |            ^^^^^^
note: required because it appears within the type `Win`
   --> /home/archer/Work/Test/src/win.rs:5:12
    |
5   | pub struct Win {
    |            ^^^
note: required because it's used within this closure
   --> src/main.rs:23:17
    |
23  |   thread::spawn(move || {
    |                 ^^^^^^^
note: required by a bound in `spawn`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1

error[E0277]: `*mut c_void` cannot be shared between threads safely
   --> src/main.rs:23:17
    |
23  |     thread::spawn(move || {
    |  ___-------------_^
    | |   |
    | |   required by a bound introduced by this call
24  | |     win.handle_events();
25  | |   });
    | |___^ `*mut c_void` cannot be shared between threads safely
    |
    = help: within `sdl3::video::WindowContext`, the trait `Sync` is not implemented for `*mut c_void`
note: required because it appears within the type `sdl3::video::WindowContext`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:544:12
    |
544 | pub struct WindowContext {
    |            ^^^^^^^^^^^^^
    = note: required for `Arc<sdl3::video::WindowContext>` to implement `Send`
note: required because it appears within the type `sdl3::video::Window`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:683:12
    |
683 | pub struct Window {
    |            ^^^^^^
note: required because it appears within the type `Win`
   --> /home/archer/Work/Test/src/win.rs:5:12
    |
5   | pub struct Win {
    |            ^^^
note: required because it's used within this closure
   --> src/main.rs:23:17
    |
23  |   thread::spawn(move || {
    |                 ^^^^^^^
note: required by a bound in `spawn`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1

error[E0277]: `*mut sdl3_sys::generated::video::SDL_Window` cannot be sent between threads safely
   --> src/main.rs:23:17
    |
23  |     thread::spawn(move || {
    |  ___-------------_^
    | |   |
    | |   required by a bound introduced by this call
24  | |     win.handle_events();
25  | |   });
    | |___^ `*mut sdl3_sys::generated::video::SDL_Window` cannot be sent between threads safely
    |
    = help: within `sdl3::video::WindowContext`, the trait `Send` is not implemented for `*mut sdl3_sys::generated::video::SDL_Window`
note: required because it appears within the type `sdl3::video::WindowContext`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:544:12
    |
544 | pub struct WindowContext {
    |            ^^^^^^^^^^^^^
    = note: required for `Arc<sdl3::video::WindowContext>` to implement `Send`
note: required because it appears within the type `sdl3::video::Window`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:683:12
    |
683 | pub struct Window {
    |            ^^^^^^
note: required because it appears within the type `Win`
   --> /home/archer/Work/Test/src/win.rs:5:12
    |
5   | pub struct Win {
    |            ^^^
note: required because it's used within this closure
   --> src/main.rs:23:17
    |
23  |   thread::spawn(move || {
    |                 ^^^^^^^
note: required by a bound in `spawn`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1

error[E0277]: `*mut c_void` cannot be sent between threads safely
   --> src/main.rs:23:17
    |
23  |     thread::spawn(move || {
    |  ___-------------_^
    | |   |
    | |   required by a bound introduced by this call
24  | |     win.handle_events();
25  | |   });
    | |___^ `*mut c_void` cannot be sent between threads safely
    |
    = help: within `sdl3::video::WindowContext`, the trait `Send` is not implemented for `*mut c_void`
note: required because it appears within the type `sdl3::video::WindowContext`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:544:12
    |
544 | pub struct WindowContext {
    |            ^^^^^^^^^^^^^
    = note: required for `Arc<sdl3::video::WindowContext>` to implement `Send`
note: required because it appears within the type `sdl3::video::Window`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:683:12
    |
683 | pub struct Window {
    |            ^^^^^^
note: required because it appears within the type `Win`
   --> /home/archer/Work/Test/src/win.rs:5:12
    |
5   | pub struct Win {
    |            ^^^
note: required because it's used within this closure
   --> src/main.rs:23:17
    |
23  |   thread::spawn(move || {
    |                 ^^^^^^^
note: required by a bound in `spawn`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1

error[E0277]: `*mut ()` cannot be shared between threads safely
   --> src/main.rs:23:17
    |
23  |     thread::spawn(move || {
    |  ___-------------_^
    | |   |
    | |   required by a bound introduced by this call
24  | |     win.handle_events();
25  | |   });
    | |___^ `*mut ()` cannot be shared between threads safely
    |
    = help: within `sdl3::video::WindowContext`, the trait `Sync` is not implemented for `*mut ()`
note: required because it appears within the type `PhantomData<*mut ()>`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/core/src/marker.rs:753:12
note: required because it appears within the type `sdl3::sdl::VideoSubsystem`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/sdl.rs:308:12
    |
308 | subsystem!(VideoSubsystem, SDL_INIT_VIDEO, VIDEO_COUNT, nosync);
    |            ^^^^^^^^^^^^^^
note: required because it appears within the type `sdl3::video::WindowContext`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:544:12
    |
544 | pub struct WindowContext {
    |            ^^^^^^^^^^^^^
    = note: required for `Arc<sdl3::video::WindowContext>` to implement `Send`
note: required because it appears within the type `sdl3::video::Window`
   --> /home/archer/.asdf/installs/rust/1.84.1/registry/src/index.crates.io-6f17d22bba15001f/sdl3-0.14.26/src/sdl3/video.rs:683:12
    |
683 | pub struct Window {
    |            ^^^^^^
note: required because it appears within the type `Win`
   --> /home/archer/Work/Test/src/win.rs:5:12
    |
5   | pub struct Win {
    |            ^^^
note: required because it's used within this closure
   --> src/main.rs:23:17
    |
23  |   thread::spawn(move || {
    |                 ^^^^^^^
note: required by a bound in `spawn`
   --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1

error[E0277]: `(dyn Fn() + 'static)` cannot be sent between threads safely
  --> src/main.rs:23:17
   |
23 |     thread::spawn(move || {
   |  ___-------------_^
   | |   |
   | |   required by a bound introduced by this call
24 | |     win.handle_events();
25 | |   });
   | |___^ `(dyn Fn() + 'static)` cannot be sent between threads safely
   |
   = help: the trait `Send` is not implemented for `(dyn Fn() + 'static)`
   = note: required for `Unique<(dyn Fn() + 'static)>` to implement `Send`
note: required because it appears within the type `Box<(dyn Fn() + 'static)>`
  --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/alloc/src/boxed.rs:233:12
   = note: required because it appears within the type `(String, Box<(dyn Fn() + 'static)>)`
   = note: required for `hashbrown::raw::RawTable<(String, Box<(dyn Fn() + 'static)>)>` to implement `Send`
note: required because it appears within the type `hashbrown::map::HashMap<String, Box<(dyn Fn() + 'static)>, RandomState>`
  --> /rust/deps/hashbrown-0.15.0/src/map.rs:185:12
note: required because it appears within the type `HashMap<String, Box<(dyn Fn() + 'static)>>`
  --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/collections/hash/map.rs:211:12
note: required because it appears within the type `Win`
  --> /home/archer/Work/Test/src/win.rs:5:12
   |
5  | pub struct Win {
   |            ^^^
note: required because it's used within this closure
  --> src/main.rs:23:17
   |
23 |   thread::spawn(move || {
   |                 ^^^^^^^
note: required by a bound in `spawn`
  --> /rustc/e71f9a9a98b0faf423844bf0ba7438f29dc27d58/library/std/src/thread/mod.rs:724:1
help: use parentheses to call this trait object
   |
25 |   }());
   |    ++

For more information about this error, try `rustc --explain E0277`.
error: could not compile `test` (bin "test") due to 8 previous errors

Подскажите как сделать правильно?

★★★★★

Последнее исправление: TDrive (всего исправлений: 1)

https://wiki.libsdl.org/SDL3/FAQDevelopment#can-i-call-sdl-event-functions-from-multiple-threads

The main event handling should be done on the main thread, though you can use SDL_PushEvent() and SDL_PeepEvents() to interact with the event queue on other threads. Most SDL functions have their thread-safety noted in their documentation.

Вообще большинство графических библиотек не позволяют обрабатывать события вне основного потока, вцелом потому что так устроен нижний уровень API.

Используемый язык тут внезапно непричём

GPFault ★★★
()
Последнее исправление: GPFault (всего исправлений: 1)
Ответ на: комментарий от anonymous

Зато раст принес на компьютер кучу непонятного кода, непонятно откуда и непонятно кем написанного. Не понятно, вообще, проверял ли его кто.

Попробуй сертифицировать код на расте - и я посмотрю, как ты будешь вертеться как уж на сковородке!

Хотя с другой стороны, вокруг раста сейчас очевидный шум. Написано очень много книг за последнее время. Это хорошо. Идет развитие.

Мне очень нравится сам язык, а вот его инфраструктуру терпеть не могу. Впрочем, у людей обычно наоборот. До самого языка обычно дела им большого нет, зато пищат от cargo…

Мне кажется, что нужно менять сам подход к инфраструктуре раста. Существующий подход пока незрелый. Пока отдает джаст-фо-фанством и прыщавостью. Хотя потенциал безусловно есть, и он просто огромен

anonymous
()
Ответ на: комментарий от anonymous

Мне очень нравится сам язык,

HashMap<String, Box<dyn Fn() -> () >>

пачка глобальных переменных зачем -то.

test::win::init(«Test», 1920, 1080); пойми что он тут объявляет, метод из файла win или инициализирует структуру, подумай минуту и пойми что наверное все-таки метод, а потому что струтура у него с большой буквы, кстати нахера она?

Box::new(move || { на каждом углу и в итоге, не могу сделать move между тредами.

Что тут может нравится? На С++ это получилось бы в разы понятнее и без ублюдочных глобальных переменных пусть и внутри неймспейса, и в разы читабельнее.

Ygor ★★★★★
()
Последнее исправление: Ygor (всего исправлений: 1)
Ответ на: комментарий от Ygor
  • i128 из коробки
  • проверка на integer overflow из коробки
  • Переосмысление null значения переменных, сделать его через enum это гениально.

пойми что он тут объявляет, метод из файла win или инициализирует структуру

cargo doc –open решает всё это, ты просто не в теме.

TDrive ★★★★★
() автор топика
Последнее исправление: TDrive (всего исправлений: 1)
Ответ на: комментарий от TDrive

i128 из коробки

Все это есть в java и сделано в гораздо более очевидным способом. А скорость работы с такими числами будет не сильно выше, чем в той же java.

Переосмысление null значения переменных:

  1. Box::new(move || - Осмысли пожалуйста нахера мне видеть низкоуровневые абстракции в высокоуровневом коде?

  2. А далее думать, а что в контейрее в итоге будет, если *d_clone_offset_x окажется null?

ты просто не в теме.

Я смотрю на эту мешанину и чот мне лезеть в тему не охота. Тем более, что отжирает это десятки гигов и диска и оперативы ради хеловорда на sdl.

Ygor ★★★★★
()
Ответ на: комментарий от Ygor

У меня ровно противоположный опыт. На расте у меня получается короче, понятнее, быстрее и получается более эффективный код, чем на С++, хотя коммерческий опыт у меня именно на C++. Впрочем, это настолько субъективно, что даже обсуждать не буду.

Если смотреть в долгую, то раст может в итоге переиграть C++, но для этого нужно решить проблему доверия к программным библиотекам раста, как я уже заметил выше. Госсектор с вами просто не будет разговаривать, если вы им предложите написать проект на rust. Посмеются только.

anonymous
()
Ответ на: комментарий от Ygor

HashMap<String, Box<dyn Fn() -> () >>

map<string, function<void(void)>>

Ну и? Кстати, вопрос: аллоцирует-ли std::function если туда засунуть лямбду с несколькими захваченными переменными?

пачка глобальных переменных зачем -то.

Э? Там нет глобальных переменных. Глобальные переменные в расте обозначаются ключевым словом static.

пойми что он тут объявляет, метод из файла win или инициализирует структуру

Документацию на язык не читал, но осуждаю?

В общем критика уровня: я тут посмотрел на испанский язык - полная херня, ничего непонятно и словари толстые.

red75prim ★★★
()
Последнее исправление: red75prim (всего исправлений: 1)
Ответ на: комментарий от TDrive

Если надо такие события обрабатывать не в главном потоке, их надо в главном потоке пробрасывать в какую-то другую трейсейф очередь, откуда выбирать уже другим тредом и обрабатывать.

А так да. Обычно такие вот фреймврки (это не про руст, а вообще) не рассчитаны на обработку своих событий вне главного треда. потому что так проще, и не требует лишних синхронизаций.

Короче, хочешь вне главного треда - диспетчеризуй ивенты в главном треде другим тредам. С учетом того, что не весь функционал таких либ умеет работать вне главного треда. Но свой тредсейф функционал писать не запрещено.

alysnix ★★★
()
Ответ на: комментарий от red75prim

Ну и? Кстати, вопрос

Во во, и таких вопросов там к каждой третьей строчке. А принесут тебе такое на рьевью, ты кому эти вопросы задавать будешь дебагу?

осуждаю

Конечно не читал, мне моё ментальное здоровье важнее.

Ygor ★★★★★
()
Ответ на: комментарий от TDrive

Я не хочу таскать с собой jvm, к тому же в джаве сборщик мусора который мне не нужен

А таскать скомпиленные компилятором раста библиотеки ты хочешь? Или ты на месте хочешь выяснять, чому оно не резолвит символы в библиотеках на целевом компе?

Ygor ★★★★★
()
Ответ на: комментарий от LongLiveUbuntu

да, ловит и переполнение и попытку уйти в минус.

https://doc.rust-lang.ru/book/ch03-02-data-types.html

Если выполняется компиляция в режиме отладки, Rust включает проверку на целочисленное переполнение, приводящую вашу программу к панике во время выполнения, когда возникает такое поведение. Rust использует термин паника(panicking), когда программа завершается с ошибкой. Мы обсудим панику более подробно в разделе "Неустранимые ошибки с panic!" в главе 9. . При компиляции в режиме release с флагом --release, Rust не включает проверки на целочисленное переполнение, которое вызывает панику. Вместо этого, в случае переполнения, Rust выполняет обёртывание второго дополнения. Проще говоря, значения, превышающие максимальное значение, которое может хранить тип, "оборачиваются" к минимальному из значений, которые может хранить тип. В случае u8 значение 256 становится 0, значение 257 становится 1, и так далее. Программа не запаникует, но переменная будет иметь значение, которое, вероятно, не будет соответствовать вашим ожиданиям. Полагаться на поведение обёртывания целочисленного переполнения считается ошибкой. Для явной обработки возможности переполнения существует семейство методов, предоставляемых стандартной библиотекой для примитивных числовых типов:

Обёртывание во всех режимах с помощью методов wrapping_*, таких как wrapping_add.
Возврат значения None при переполнении с помощью методов checked_*.
Возврат значения и логический индикатор, указывающий, произошло ли переполнение при использовании методов overflowing_*.
Насыщение минимальным или максимальным значением с помощью методов saturating_*.
TDrive ★★★★★
() автор топика
Ответ на: комментарий от TDrive

Проще говоря, значения, превышающие максимальное значение, которое может хранить тип, «оборачиваются» к минимальному из значений, которые может хранить тип. В случае u8 значение 256 становится 0, значение 257 становится 1, и так далее. Программа не запаникует, но переменная будет иметь значение, которое, вероятно, не будет соответствовать вашим ожиданиям. Полагаться на поведение обёртывания целочисленного переполнения считается ошибкой.

То есть целочисленное переполнение для беззнаковых типов не отолавливается, как и должно быть. А я уж думал, они чудо сотворили.

LongLiveUbuntu ★★★★★
()
Ответ на: комментарий от LongLiveUbuntu
fn main() {
  let mut n: u8 = 255;
  n += 1;
  println!("{:?}", n);
}
thread 'main' panicked at src/main.rs:6:3:
attempt to add with overflow
fn main() {
  let mut n: u8 = 0;
  n -= 1;
  println!("{:?}", n);
}
thread 'main' panicked at src/main.rs:6:3:
attempt to subtract with overflow

Что ещё нужно?

TDrive ★★★★★
() автор топика
Ответ на: комментарий от TDrive

Потому что Бьёрн Страуструп 40 лет х*и пинал вместо того, чтобы работать над языком.

рантайм контроль переполнения и в с++ есть. там и -fsanitize и всякие встроенные функции с контролем переполнения.

проблема проверки переполнений в том, что это лишний код джампа по биту переполнения. это внутри арифметических выражений.

то есть код с проверками будет куда длиннее кода без проверок, плюс джампы, что мешают всяким там спекуляциям.

и если для всяких там недоязычкам на эти мелочи положить, то для плюсищ это вопрос принципиальный. хочешь проверок - делай сам.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

Вот я специально кусок из доки раста процитировал. Проверки в rust работают в дебаг режиме, он по умолчанию, пока занимаешься разработкой. Если скомпилировать с флагом –release проверок не будет. При этом есть готовые методы которые могут вернуть проверки и для release если нужно. Всё, это в принципе всё что нужно чтобы не еб**ь себе мозг во время разработки и не терять производительность в релизе.

TDrive ★★★★★
() автор топика

Проблема переполнений в том, что в большинстве кода это каждый раз является ошибкой. Осознанно переполнения используются где-нибудь в криптографии и в реализации хеш функций. Ну может еще где-нибудь.

Но для обычного кода, когда в случае расчетов очень большое значение вдруг становится очень маленьким или превращается в ноль является неожиданным и портит весь алгоритм. Еще и труднообнаружимый, т.к. проявляется только при очень больших объемах данных или при атаках. Предсказать и тестами покрыть сложно.

То что есть ub при переполнении знаковых чисел чисто искусственная оптимизация, дающая выигрыш в некоторых ситуация, ее можно и отключить. Только в этом нет смысла, т.к. если у тебя переменная неожиданно скачет между своими крайними положениями, у тебя и так уже проблемы.

anonymous
()

В SDL2 эвент луп должен быть в основном потоке, в SDL3 можно вынести чтоль? O_O, или события пересылаешь в другой поток из основного? Я с моделью потоков раста не знаком, но так-то вроде единственный способ (для например pthread) это в евент лупе основного процесса получать события и отправлять их в некую свою очередь которую обрабатывает цикл во внешнем процессе и что-то на основе этого делает.

Типа

  • событие
  • вешаем лок, добавляем в очередь событие снимаем лок
  • вешаем лок, вызываем во внешнем процессе функцию которая извлечёт следующее событие, снимаем лок

Но это для сишки…

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от zurg

хех, а в виндовсе, оказывается, можно цикл сообщений и не в главном потоке создавать https://docs.rs/winit/latest/x86_64-pc-windows-msvc/winit/platform/windows/trait.EventLoopBuilderExtWindows.html# Ну и зачем связываться с sdl-ями, в расте же своя универсальная рисовалка есть- wgpu

zurg
()
Последнее исправление: zurg (всего исправлений: 1)
Ответ на: комментарий от zurg

хех, а в виндовсе, оказывается, можно цикл сообщений и не в главном потоке создавать

Да, там все продуманно уже давно и хорошо сделано в отличие от Linux. Но суть SDL как раз в том, что бы приложение запускалось везде, и он поддерживает намного больше платформ чем wgpu.

MOPKOBKA ★★★★★
()
Ответ на: комментарий от alysnix

для плюсищ это вопрос принципиальный. хочешь проверок - делай сам.

Т.е. вместо проверки бита переноса, который недоступен из c++, нужно городить if-ы с проверкой результата? Хотя что я, глупости какие, у цпп богатая стд, там даже std::launder есть, найдётся и ckd_add, само собой, да? Что, доступно уже в c++26? Шикарный язык, да.

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

ключег -ftrapv gcc для генерации кода перехвата переполнений.

https://gist.github.com/mastbaum/1004768

но это хорошо работает там, где аппаратно происходит прерывание по переполнению. а в интеловской архитектуре этого нет, там просто выставляются биты.

Потому для перехвата нужно биты явно проверять после каждой арифметической команды. Что увеличивает код и делает его медленней.

alysnix ★★★
()
Ответ на: комментарий от unC0Rr

«ключег -ftrapv gcc для генерации кода перехвата переполнений» не входит в стандарт.

и что? по жизни нужны три вида арифметики - циклическая(игнорируем переполнение), с перехватом переполнения(сигналим) и с переносом (не сигналим, расширяем результат). может еще какие виды.

если все это вводить в стандарт - то как-то жирно получается.

а в плюсах, за счет переопределения операторов, вы можете нарисовать любую арифметику.

вообще с переполнением борются правильным выбором типа операндов, а не перехватом и обработкой ошибки. ибо делать это в рантайме, если аппаратура не поддерживает, слишком затратно.

ps вот примерчик контроля переполнения. оверхед просто чудовищный. чтобы посмотреть, что будет без контроля - убрать -ftrapv из опций компилятора

https://godbolt.org/z/zv3Tbnvra

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от GPFault

Вообще большинство графических библиотек не позволяют обрабатывать события вне основного потока

На самом деле в большинстве из них это никак не регламентируется, но не считается основным способом использования, поэтому «не то чтоб не рекомендуется, но… ты не захочешь» и «не надо оно тебе»(тм). И реализация этого полностью ложится на мсье, знающего толк в. В тех же кутях, например, исторически можно крутить в отдельном потоке, но надо прокачивать очередь событий, дергая метод processEvents() в этом отдельном цикле. Это сопряжено с рядом граблей начиная от неудобств такого способа до обеспечения синхронизации потоков и особенностей взаимодействия конкретных версий кутей с тем же xcb и через них с дровами и чревато поломками, т.к. происходят breaking changes. В sdl плюс-минус такой же «ряд нюансов», особенно если приложение изначально не завязано на какой-то гуевый тулкит, но в процессе возникает необходимость его с ним сопрячь, а не переписывать «заного». (Отдельный раздел камасутры в матрицу этого секса добавляется вместе с ржавчиной, как у ТСа, это вот «когда добавляю тред начинается какой то ад с владением над переменными и полная консоль ошибок»)

anonymous
()