this post was submitted on 17 Jul 2024
5 points (100.0% liked)

Learning Rust and Lemmy

391 readers
1 users here now

Welcome

A collaborative space for people to work together on learning Rust, learning about the Lemmy code base, discussing whatever confusions or difficulties we're having in these endeavours, and solving problems, including, hopefully, some contributions back to the Lemmy code base.

Rules TL;DR: Be nice, constructive, and focus on learning and working together on understanding Rust and Lemmy.


Running Projects


Policies and Purposes

  1. This is a place to learn and work together.
  2. Questions and curiosity is welcome and encouraged.
  3. This isn't a technical support community. Those with technical knowledge and experienced aren't obliged to help, though such is very welcome. This is closer to a library of study groups than stackoverflow. Though, forming a repository of useful information would be a good side effect.
  4. This isn't an issue tracker for Lemmy (or Rust) or a place for suggestions. Instead, it's where the nature of an issue, what possible solutions might exist and how they could be or were implemented can be discussed, or, where the means by which a particular suggestion could be implemented is discussed.

See also:

Rules

  1. Lemmy.ml rule 2 applies strongly: "Be respectful, even when disagreeing. Everyone should feel welcome" (see Dessalines's post). This is a constructive space.
  2. Don't demean, intimidate or do anything that isn't constructive and encouraging to anyone trying to learn or understand. People should feel free to ask questions, be curious, and fill their gaps knowledge and understanding.
  3. Posts and comments should be (more or less) within scope (on which see Policies and Purposes above).
  4. See the Lemmy Code of Conduct
  5. Where applicable, rules should be interpreted in light of the Policies and Purposes.

Relevant links and Related Communities


Thumbnail and banner generated by ChatGPT.

founded 9 months ago
MODERATORS
 

This pertains to Ch 16.03 of The Book, specifically Arc in multithreaded programs

I was just looking at the signature for thread::spawn (documentation linked to by post URL) wondering if and how the requirement for a thread-safe smart pointer is enforced by the type system. In short, how is the use of Arc necessitated by the type system??

For the signature, you get this:

pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
    F: FnOnce() -> T + Send + 'static,
    T: Send + 'static,

Where the parameter f is bound by F: FnOnce() -> T + Send + 'static.

And ... I'm not entirely sure how I should think about this.

Obviously, Send and 'static here are related to my question, where in some way the closure must be thread-safe (through the Send trait) and also have a whole-life-of-the-program lifetime (through the 'static lifetime). Therefore, in some way, something like Rc would be invalid but Arc would be.

But how exactly?

  1. Are the bounds on the return type of the function/closure, which then sort of back propagate onto the input parameters or captured values of the function/closure?
  2. Or are these somehow properties of the function itself?
  3. And why is T separately bound by Send + 'static when they are already present in the bounds on F?

My best guess is that the bounds on F are best parsed as ...

F: ( FnOnce() -> T ) + Send + 'static
T: Send + 'static

IE, Everything separated by a + is unitary, and, therefore, FnOnce() -> T is a single bound and Send another separate bound.

But I'm unsure about that, haven't read that anywhere, and am not really sure how to understand how exactly a function can have Send or 'static without some logic linking that directly to its input parameters?

Thoughts?

you are viewing a single comment's thread
view the rest of the comments
[–] Ogeon@programming.dev 2 points 4 months ago* (last edited 4 months ago) (3 children)

Your guess is correct, it should be understood as

F: ( FnOnce() -> T ) + Send + 'static
T: Send + 'static

The FnOnce() -> T is syntax sugar for FnOnce<(), Output = T> and the bounds after apply to F. That's also why T has separate bounds. They aren't propagated or inherited. It's just an ambiguous looking syntax, but T + Trait + 'lifetime isn't a valid syntax for applying bounds to T (unless I missed something).

The type F may be a closure over values from the calling thread. It has to be possible to send these values to the spawned thread, hence F needs Send + 'static. When the thread is done with its work, it returns a value of type T that gets passed back via JoinHandle<T>, so T needs Send + 'static too.

I hope this cleared things up a bit.

[–] maegul@lemmy.ml 2 points 4 months ago (2 children)

Thanks!! (Am I correct in guessing that you handle is of Gontian origin?)

Clears up a lot!

It has to be possible to send these values to the spawned thread, hence F needs Send + 'static.

I'm still not sure I understand what this means. I suppose it's normal for a function/closure to have a lifetime, though how a closure comes to be 'static I'm not sure. And similarly I'm not clear on how a function/closure would come to have Send.

I'm guessing from your language that these bounds come from the captured values? That is, whether they are satisfied depends on whether the captured values satisfy them?

[–] Ogeon@programming.dev 2 points 4 months ago (1 children)

A closure may/will try to capture by reference, so it may hold references to the calling function's scope. For example, this would want to hold a reference to x:

let x = 0;
std::thread::spawn(|| x += 1);

It's as if you had a struct like this:

struct MyClosure<'a> {
    x: &'a mut i32,
}

That makes the closure non-'static, since it holds non-'static references. The usual solution is to use the move keyword, to hint that you want it to move by default, or to use scoped threads. But yeah Send and 'static depend on the captures.

Am I correct in guessing that you handle is of Gontian origin?

Yes! 😁 I picked it when I used to play Tibia (15-20 years ago!), and it stuck with me since then. The correct spelling was already taken, so I modified it a bit. This name is usually available.

[–] maegul@lemmy.ml 2 points 4 months ago

Thanks so much!!

And yea, nice handle! Mine’s kinda similar. It comes from Tolkien, I used it for an MMORPG back in the day and it’s kinda stuck as it’s almost always available.