Amanieu / parking_lot

Compact and efficient synchronization primitives for Rust. Also provides an API for creating custom synchronization primitives.
Apache License 2.0
2.77k stars 217 forks source link

Forcing Send on a guard when using genawaiter #373

Closed fabianmurariu closed 1 year ago

fabianmurariu commented 1 year ago

This is more of a question rather than an issue, we're using parking_lot with genawaiter to get an iterator without lifetime from a struct.

    struct Example<T>(Arc<parking_lot::RwLock<Vec<T>>>);

    impl<T: Clone> Example<T> {
        fn iter(&self) -> impl Iterator<Item = T> {
            let tgshard = self.0.clone();
            let iter: GenBoxed<T> = GenBoxed::new_boxed(|co| async move {
                let g = tgshard.read();
                let iter = (*g).iter();
                for t in iter {
                    co.yield_(t.clone()).await;
                }
            });

            iter.into_iter()
        }
    }

this is not allowed by the rust compiler because the guard is not Send.

However, is forcing the guard in this scenario (using genawaiter ) to be Send an actual problem? I don't think the guard will be moved onto another thread. (that being said I have no clue how genawaiter works)

Basically is this workable?

    struct MyLock<T>(parking_lot::RwLock<T>);
    struct MyGuard<'a, T>(parking_lot::RwLockReadGuard<'a, T>);

    impl<T: Clone> MyLock<T> {
        fn read(&self) -> MyGuard<T> {
            MyGuard(self.0.read())
        }
    }

    impl<T> Deref for MyGuard<'_, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            self.0.deref()
        }
    }

    unsafe impl<T> Send for MyGuard<'_, T> {}

    struct Example2<T>(Arc<MyLock<Vec<T>>>);

    impl<T: Clone + std::marker::Send + std::marker::Sync + 'static> Example2<T> {
        fn iter(&self) -> impl Iterator<Item = T> {
            let tgshard = self.0.clone();
            let iter: GenBoxed<T> = GenBoxed::new_boxed(|co| async move {
                let g = tgshard.read();
                let iter = (*g).iter();
                for t in iter {
                    co.yield_(t.clone()).await;
                }
            });

            iter.into_iter()
        }
    }
bjorn3 commented 1 year ago

You are using genawaiter::sync::GenBoxed which is explicitly meant for the case where the generator will be sent across threads AFAICT. Try using genawaiter::rc::Gen instead which doesn't require Send.

fabianmurariu commented 1 year ago

Thanks for the help