Question regarding trait bounds for some closures in gstreamer-rs

Steven Fontaine sir.fon1103 at gmail.com
Sun Feb 20 12:14:19 UTC 2022


Hi Sebastian,

> It's a bit unfortunate that the `std::sync::mpsc::Sender` is not `Sync`
> but you don't need the full `Arc<Mutex<_>>` machinery for making this
> work.
>
> You can move the sender into your callback, `clone()` it every time you
> need to send something through it and use the clone for sending.
>
> Internally the sender uses an `Arc` etc. so this is cheap, and cheaper
> than putting another `Mutex` around everything.

To provide a brief snippet of code, here's roughly what I'm doing:

// SNIPPET

// gst/glutin boilerplate
let event_loop = glutin::event_loop::EventLoop::new();
// more gst/glutin boilerplate
let decodebin = gst::ElementFactory::make("decodebin", None).unwrap();
// etc...
let event_loop_proxy = Arc::new(Mutex::new(event_loop.create_proxy()));
decodebin.connect_pad_added(move |dbin, src_pad| {
    // ...
    let appsink = gst::ElementFactory::make("appsink", None)
        .unwrap()
        .dynamic_cast::<gst_app::AppSink>()
        .unwrap();
    let event_loop_proxy = event_loop_proxy.clone();
    appsink.set_callbacks(gst_app::AppSinkCallbacks::builder()
        .new_sample(move |appsink| {
            let el = event_loop_proxy.lock().unwrap();
            el.send_event(/* event */);
            // etc
        }).build(),
    );
    // ...
});

// END SNIPPET

If I understand your suggestion correctly, you're saying that the Arc+Mutex
shouldn't be required, and I can simply clone the event loop proxy (which
is replaceable with an mpsc channel for this example) and send that into
the first closure, then inside that closure, clone it again and send it
into the appsink closure. However, this is exactly what I was trying before
moving to the Arc+Mutex approach, as attempting to move the cloned event
loop (or mpsc sender) into only the decodebin closure causes rust to
complain about the event loop not being Sync. For instance, attempting the
following:

// SNIPPET

// gst/glutin boilerplate
let event_loop = glutin::event_loop::EventLoop::new();
// more gst/glutin boilerplate
let decodebin = gst::ElementFactory::make("decodebin", None).unwrap();
// etc...
// (This will also fail if I clone the proxy prior to attempting to move
it. However,
// cloning it shouldn't be required in the first place since I'm not using
the
// proxy outside of the closure.)
let event_loop_proxy = event_loop.create_proxy();
decodebin.connect_pad_added(move |dbin, src_pad| {
    // ...
    let appsink = gst::ElementFactory::make("appsink", None)
        .unwrap()
        .dynamic_cast::<gst_app::AppSink>()
        .unwrap();
    let event_loop_proxy_clone = event_loop_proxy.clone();
    appsink.set_callbacks(gst_app::AppSinkCallbacks::builder()
        .new_sample(move |appsink| {
             event_loop_proxy_clone.send_event(/* event */);
            // etc
        }).build(),
    );
    // ...
});

// END SNIPPET

fails at line "decodebin.connect_pad_added ..." with the following:
> `std::sync::mpsc::Sender<Message>` cannot be shared between threads safely
> help: within `[closure at src\main.rs:_:_: _:_]`, the trait
`std::marker::Sync` is not implemented for
`std::sync::mpsc::Sender<Message>`
> note: required because it appears within the type `[closure at src\main.rs:_:_:
_:_]`

Am I misunderstanding your suggestion?

Regarding crossbeam, the Sender which rustc is referring to here lives
within a glutin::event_loop::EventLoop, so a crossbeam channel wouldn't be
a drop-in replacement. It would be fairly trivial to make it work, but I'd
like to avoid additional dependencies if I can. That said, if a crossbeam
channel ends up being the most efficient option, that's certainly what I'll
go with.

Thanks,
Steven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20220220/a3fe0e86/attachment.htm>


More information about the gstreamer-devel mailing list