Crust of Rust: Send, Sync, and their implementors

preview_player
Показать описание


0:00:00 Why Send and Sync?
0:01:31 What are Send and Sync?
0:02:51 Marker traits
0:03:50 Auto traits
0:05:45 The Send trait
0:06:49 Types that aren't Send
0:09:40 Digging into Rc
0:23:52 The Sync trait
0:26:21 Send + !Sync
0:32:41 Negative implementations
0:35:17 Sending mutable references
0:37:00 Raw pointers
0:41:54 std::sync::mpsc and !Sync
0:42:30 Placement of T: Send/Sync bounds
0:46:04 Per-OS impl Send for guards
0:47:06 more std::sync::mpsc and !Sync
0:48:40 Is Send/Sync auto-implemented?
0:50:40 The nomicon Send/Sync entry
0:52:57 There's no magic!
1:02:46 Negative impls on stable
Рекомендации по теме
Комментарии
Автор

I looked at the channel yesterday and was sad to see no new videos for 3 months. Just now I wake up to a new video notification. Today is a good day!

Kaiwa
Автор

Thanks a lot! I feel that for this particular topic there was no clear explanation for us who didn't understand the design decisions beforehand.

Ok, just to check that I got it all right, I understand that we can have:
- Send + Sync: applies to "most" types, no restrictions.
- !Send + Sync: cross-thread transfer of ownership is not fine, but transfer of a &-reference is fine.
Other threads can access the value but are not allowed to drop it, nor &mut-modify it.
Prototypical example: lock guards (like MutexGuard<T>), "per-thread" allocation via thread_local/TLS (?).
- !Send + !Sync: neither owned nor &-reference transfer are sound. This is because there are methods accessible via &-references that break some invariant if called from a different thread.
Prototypical example: Rc<T>, it is !Send because of its non-atomic reference counter (can cause a double-free (UB!) or leak (not so serious)), !Sync because clone() also manipulates said counter. Arc is Send + Sync by using atomics (performance tradeoff).
Raw pointers are purposefully !Send + !Sync to "contaminate" any enclosing types, just as an extra security measure.
- Send + !Sync: weirdest case, this applies when we want to have all references in the same thread as the owning one, but as the same time we want to allow cross-thread ownership transfer. This is the case of interior mutability wrapper types.
Prototypical example: {, Ref, Unsafe}Cell.

japedr
Автор

Thank you for your time and effort. Very much appreciated!

fbytgeek
Автор

Really enjoyed the video. Feel like I understand send and sync better now

michaelr
Автор

please keep doing crust of rust!! thank you!

dimitrimitropoulos
Автор

31:50 It's not solely about multithreading that makes mutation from behind a shared reference dangerous. Imagine the data has a Vec, and someone has a direct reference into the Vec (gained by Vec::get()), and you push a new item and it re-allocates the Vec, making that reference point into deallocated memory.

I guess that's why Cell doesn't implement Borrow / doesn't allow you to get a shared reference, only to replace the value entirely?

karelhrkal
Автор

Great content, many thanks for all time and effort

samuel.ibarra
Автор

11:10 T does not have to be Clone in Rc<T>
11:45 If &mut is omitted, the code would still work, as dereferencing a mutable raw pointer (self.inner: *mut Inner<T>) gives mutable access to Inner<T>
13:10 &unsafe { &*self.inner }.value: &* dereferences the raw pointer and casts the Inner<T> to a shared reference, & casts the value to a shared reference
25:30 MutexGuard is Sync + !Send, Rc is !Send (clone Rc and send to another thread, reference count is not atomic) + !Sync (send &Rc to another thread and call clone, requires all access happens on one thread)
28:40 Cell is Send + !Sync, can't get reference to Cell in another thread, therefore safe to mutate in current thread as no other reference is mutating it. T must also implement Send + !Sync.
31:00 Application of Cell in graph traversal (can't take exclusive references, could walk same node), Cell allows mutation through a shared reference
36:20 If &mut T is Send, then T must be Send (std::mem::replace)
45:00 T is Sync because all the Arc instances reference T, T is Send because the last Arc must drop the inner type
46:00 &T is Send if T is Sync
47:30? Sender is !Sync, multiple shared references to Sender but only one in each thread
54:30 dyn syntax allows only one trait, exceptions are auto traits (Send, Sync)
59:50 thread::spawn requires type is 'static & and Send, not Sync as it doesn't take references
1:00:40 thread::scope does not need 'static & arguments, current thread can't return until scoped thread joined

CPTSLEARNER
Автор

It seems impl<'_, T> Send for &'_ mut T where T: Send + ?Sized is no longer present in rust doc. Is what you said at 35:17 still correct?

理塘丁真-jp
Автор

Great video, really interesting to listen to you, keep up the good work!

beastleend
Автор

how can I get notifs for livestreams? these videos are literally the highlight of my YouTube watch history

askii
Автор

Thank you, I want know what's your editor font.

LeoD-dj
Автор

23:15 worse yet, two threads concurrently increment, but both increment it to the same value - then, a few drops later and somebody has a pointer - as far as the compiler is concerned - into the depths of hell.

kennichdendenn
Автор

You mention that !Send is sometimes manually (un)implemented for types that rely on thread-locals. Does that mean that auto implementation of Send may cause unsoundness/UB? Or is it "solved" by thread-locals being inherently unsafe to use?

KohuGaly
Автор

non related question: what is your terminal font? looks really good and readable for coding

alexzander__
Автор

59:01: `static`s also require at least Sync

thepuzzlemaker
Автор

great vid! could you please share your vim plugins?

NKBrick
Автор

Isn't your RC implementation UB? Is it fine to dereference a *mut pointer inside a struct through &self? You said it's technically safe because there is no multiple write access to that field and this is correct without Send and Sync but isn't going from & to &mut always UB? Even for struct fields?

Lexikon
Автор

Audio and video seem to be a little out of sync. I watched it with ~ -250ms for audio in VLC. The live version was fine thou when I watched it briefly, but I might be wrong.
Aside from that awesome video as always.

TTrippleT
Автор

I never understood why "duplicating" the Rc is implemented with "Clone". When I clone something, I expect a deep copy, and Rc breaks that. In other words, if I clone it, then mutate the clone, the original is mutated as well! What a mess, honestly.

karelhrkal