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)
Ответ на: комментарий от alysnix

Ещё бывает с насыщением. Я не понимаю, как может быть жирно вводить в стандарт самые элементарные операции, которые невыразимы в оптимальном виде в рамках языка. В стандарт, в котором уже есть комплексные и рациональные числа, отдельные функции для вычисления числа в степени -1/3, для НОД и среднего из двух чисел.

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

зачем вам бороться с переполнением

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

alysnix ★★★
()
Ответ на: комментарий от unC0Rr
with Ada.Text_IO;
procedure Main is
  X: Float := 100000.0;
begin
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  X := X * 1234567.0;
  Ada.Text_IO.Put_Line(Float'Image(X));
  X := 10.0;
  X := 10.0 - X;
  X := X / X;
  Ada.Text_IO.Put_Line(Float'Image(X));
  Ada.Text_IO.Put_Line("Safety!");
end Main;

Вывод:

+Inf*******
NaN********
Safety!
Вот она безопасность, пусть ракета летит в NaN.

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

Причем тут вещественные числа, когда разговор идет об переполнении целочисленных? Внезапно, на сях/расте при переполнении вещественных чисел ты так же получишь +Inf

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

Внезапно, на сях/расте при переполнении вещественных чисел ты так же получишь +Inf

#include <stdio.h>
#include <fenv.h>

int main(void)
{
  feenableexcept(FE_ALL_EXCEPT);

  float x = 10.0;
  x = 10.0 - x;
  x = x / x;
  printf("%f\n", x);
  return 0;
}
$ ./a.out
Исключение в операции с плавающей точкой

Причем тут вещественные числа, когда разговор идет об переполнении целочисленных?

А почему должно быть исключение? Ну давай тогда и int исключим, останется только unsigned который совершенно законно переполняется в С.

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

контроль переполнения интов слишком дорого стоит. не менее пары раз по скорости операций(а может и больше, поверять надо но лень).

разумные существа с планеты Земля не будут такое использовать, а всякие инопланетяне и рептилоиды - запросто.

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

Уважаемая МОРКОВКА, это получается, что ты не реализовывал численные методы?

А то картина маслом: блок управления станцией споткнулся о NaN и вместо того, чтобы локально вернуть NaN для последующей обработки, этот блок решил самоустраниться, выпасть в корку с исключением и оставить станцию без какого-либо управления.

Я правильно понимаю твой сценарий?

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

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

Сразу вспоминается история с Burroughs B5000, где в Fortran был введен bound-checking, и многие программы сразу посыпались, хотя с них раньше снимали результаты... Обидно, правда? Ты бы наверное просто отключил проверку выхода за границу, нормально же работало.

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

Тут такое дело, что NaN может быть особенностью конкретной математической задачи. Вот, когда ты был студентом, вас же заставляли находить точки разрыва? Это нормально. Во многих численных методах такие точки являются неотъемлемой частью задачи. Другое дело, что с ними нужно что-то делать, но вылетать из программы - это часто худшее, что может предложить программист.

Ближе к программистской реальности. Вот есть таймаут по соединению с удаленным узлом. То, что ты предлагаешь, это примерно как завершать немедленно выполнение программы только потому, что отвалилась сетка. Ты же понимаешь, что отвал сети - это естественное событие в мире сетевого программирования. Вот и точки разрыва, особые точки и все эти NaN - это тоже естественная, часто неотъемлемая часть всех этих численных методов. Их обрабатывать надо, а не закапывать голову в песок как страус

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

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

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

Я недавно провел тест, где для каждого элемента массива int[], выполнятся один инкремент. Сражались два массива, один int другой _Atomic int, разница в коде только в виде префикса lock, и с lock-префиксом тест длился в 3 раза дольше.

(атомки) не стоят ничего практически
alysnix std::shared_ptr и оверхеды (комментарий)

Как и с atomic, переполнение int не обязательно должно быть везде, компиляторы могут много где вывести отсутствие нужности проверки.

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

https://godbolt.org/z/TbcqMfT99

это clang, он вроде попроще код(прям как на асме пишут) генерит для проверок-то

функция

int over(int fn, int fnn, int fnnn) {
    return fn + fnn + fnnn*100;
}

с проверкой int переполнения

over(int, int, int):
 add    edi,esi
 jo     10 <over(int, int, int)+0x10>
 imul   eax,edx,0x64
 jo     14 <over(int, int, int)+0x14>
 add    edi,eax
 jo     10 <over(int, int, int)+0x10>
 mov    eax,edi
 ret
 ud1    eax,DWORD PTR [eax]
 ud1    eax,DWORD PTR [eax+0xc]

без проверки

over(int, int, int):
 imul   eax,edx,0x64
 add    eax,edi
 add    eax,esi
 ret

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

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

пример плохой. и функция там инлайнится. и вообще ее видит компилятор.

в 99.9 процентов случаев компилятор будет ее компилировать отдельно от контекста использования. и проверки внутри нее будут.

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

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

в 99.9 процентов случаев компилятор будет ее компилировать отдельно от контекста использования.

В релизной сборке надо использовать lto, pgo.

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

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

Обычно в хорошей программе есть проверка входных данных. С добавлением в С++ pre/post можно компилятору давать подсказки даже там, где в коде встречаются проблема остановки. И он будет вставлять проверки на переполнения только в малом количестве операций.

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

дальше компилятор сам догадывается какой возможный диапазон у значений

запросто! в простейших случаях, не играющих существенной роли.

вот довольно тривиальный код, в котором clang ставит проверки переполнения. там значение будет - 0. один раз сложатся три нуля.

https://godbolt.org/z/qWqa13Pfx

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

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

было бы странно, если б такая оптимизация активно убирала проверки переполнения.

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

вот довольно тривиальный код, в котором clang ставит проверки переполнения

clang вообще довольно плохой компилятор, но тут у тебя нету static или lto, я вот расширил шаги, и как видишь, компилятор понимает какие значения могут появится в step2, и не генерирует printf: https://godbolt.org/z/85cbvaq9E

Для реально сложных случаев, я уже написал что есть pre/post: https://en.cppreference.com/w/cpp/language/contracts, они позволяют указать как будет идти преобразование в функции, и там же можно задать компилятору новый диапазон, эти pre/post находятся прямо в прототипе функции.

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

Есть разные виды lto, ты описываешь какой то легкий, но тоже полезный в крупных программах, а я говорю о полноценном, где сохраняется внутреннее представление компилятора, и возможно проводить сложные оптимизации. С таким внутреннем представлением, которое достается оптимизатору lto, работает gcc analyzer, а как ты понимаешь, статическому анализатору надо много информации, и она на входе к lto есть.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)

Аппаратные исключения с вещественными числами тоже ни разу не бесплатные. Поэтому одним из результатов включения fast math как раз и является то, что эти исключения выключаются. Если бы они были бы бесплатными, никто бы их не выключал.

Тут такое дело, что NaN может быть особенностью конкретной математической задачи

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

Дефолтные параметры должны быть удобны для большинства задач, а не быть упорытыми или замедленными только из-за того, что если их изменить отвалится какая-то древняя математическая либа без поддержки, которая завязана на какие-то особенности странных решений стандартов (NaN != NaN).

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

clang вообще довольно плохой компилятор, но тут у тебя нету static или lto, я вот расширил шаги, и как видишь, компилятор понимает какие значения могут появится в step2, и не генерирует printf

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

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

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

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

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

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

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

Именно так работает lto, функции превращаются в статические для компилятора, и он проводит глубокую оптимизацию.

ты делаешь ставку на тривиально упрощаемый код, который в нормальной проге и существовать не будет.

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

Конечно, в некоторых местах нельзя будет отказаться от проверок, но я считаю 1) таких мест будет крайне мало, 2) проверкам в таком сложном коде самое место, потому что программист его скорее всего тоже не сможет выполнить в общем случае в голове.

Попробуй лучше предоставить код, где проверка ну прям лишняя, а статически от нее не отказаться.

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

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

MOPKOBKA ★★★★★
()
17 июня 2025 г.
Ответ на: комментарий от TDrive

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

  1. Хамство не украшает человека
  2. Вам до Бьёрн Страуструпса как свинье до неба

PS: Rust`исты они все такие высокомерный хамы?

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

Просто попробуй написать что нибудь на rust и ты сам всё поймёшь

Что я должен понять? Бьёрн Страуструпс для IT сделал больше чем вы,я и большинство тут обитающих. Что как то непозволительно Хамское отношение.

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

rust даже и не пытается быть совместимым с с (zig может например например)

и блин с++ не случайно так названы а как шутка что по факту это с если не использовать «особенности» ( после ansiiC 89/90 это перестало так быть)

qulinxao3 ★☆
()