代码之家  ›  专栏  ›  技术社区  ›  LucioleMaléfique

线程问题创建自己的winit事件线程

  •  0
  • LucioleMaléfique  · 技术社区  · 3 年前

    我正在使用 winit 创建一个应用程序,我想要我自己的主循环,而不是winit似乎强制执行的循环(我的应用程序中可能没有窗口,所以我不能依赖winit循环)。

    我的第一个直觉是生成一个线程并在其中运行winit循环,然后使用一个通道发送所有winit事件,在我的主循环中,用接收器检查这些事件。

    它看起来是这样的:

    let event_loop = EventLoopBuilder::<MyEventEnum>::with_user_event().build();
    let window = WindowBuilder::new().build(&event_loop).unwrap();
    
    let (sender, receiver) = channel::<Event<'static, MyEventEnum>>();
    
    thread::spawn(move || event_loop.run(move |event, _, control_flow| {
        // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
        // dispatched any events. This is ideal for games and similar applications.
        control_flow.set_poll();
    
        sender.send(event.clone());
    }));
    

    但这引发了错误:

    *mut ()` cannot be sent between threads safely
    within `[closure@src\window.rs:22:23: 22:30]`, the trait `Send` is not implemented for `*mut ()
    

    由于我对异步和线程还很陌生,所以我不太明白这里会发生什么。我猜线程可以获得event_loop的所有权,即使线程在我失去接收器时惊慌失措或继续运行,我通过通道通信的事实也足够安全吗?

    发生了什么事?这样的事情可能发生吗?

    0 回复  |  直到 3 年前
        1
  •  1
  •   Kevin Reid    3 年前

    你必须 创造 同一线程中的事件循环 run() 它。这是 specifically required by winit :

    请注意,这不能在线程之间共享(由于依赖于平台的逻辑禁止它),因此两者都不是 Send 也没有 Sync 。如果您需要跨线程访问,则 Window 由此创建的可以发送到其他线程,并且 EventLoopProxy 让你醒来 EventLoop 来自另一个线程。

    你可以让线程发送 和/或 EventLoopProxy 而是转到频道上的另一个线程。

    thread::spawn(move || {
        let event_loop = EventLoopBuilder::<MyEventEnum>::with_user_event().build();
        let window = WindowBuilder::new().build(&event_loop).unwrap();
    
        some_channel.send(window);
    
        event_loop.run(move |event, _, control_flow| {
            ...
        })
    });
    

    您还会发现无法发送 Event 或者,在不同的一生中,他们的一生不是 'static 。而不是发送 winit 的事件,则必须将它们转换为您自己的事件类型。无论如何,异步处理所有事件通常也不是一个好主意——这可能会导致用户界面以特殊的方式运行。相反,您应该处理事件循环线程上的单个事件以进行单击和绘制等操作,然后发送更多 高级 事件(“启动此操作”之类的事情)发送到应用程序其他线程上的其余部分。