Skip to content

Revamped "Threads" documentation #21152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 5, 2015
Merged

Revamped "Threads" documentation #21152

merged 1 commit into from
Feb 5, 2015

Conversation

steveklabnik
Copy link
Member

This moves the "Tasks" chapter to a "Concurrency" one, as it's about threads, but also about how to deal with concurrency issues.

r? @aturon

@@ -0,0 +1,343 @@
% Concurrency

Concurrency and paralellism are incredibly important topics in computer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/paralellism/parallelism/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh, I thought I had spellcheck on, but I guess not. Thanks for all the saves here.

@steveklabnik
Copy link
Member Author

I need to rebase this, and #2080 should be addressed too.

@steveklabnik steveklabnik force-pushed the tasks branch 2 times, most recently from 1ecc754 to ac4581f Compare January 21, 2015 16:45
@steveklabnik
Copy link
Member Author

Rebased and fixed up. @aturon , r?

## Background: `Send` and `Sync`

Concurrency is difficult to reason about. In Rust, we have a strong, static type
system to help us reason about our code. As such, Rust gives us two types to help
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that Send and Sync are traits, not types -- they are markers that can be applied to other types.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may also want to say something about the fact that Send and Sync are automatically applied to types.

@steveklabnik
Copy link
Member Author

@aturon I tried to address all of your points, so this is ready for another review :)

```

First, we call `lock()`, which aquires the mutex's lock. Because this may fail,
it returns an `Option<T>`, and because this is just an example, we `unwrap()`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lock actually returns a Result, and it's maybe worth saying that it fails if a thread previously holding the lock panicked.

@aturon
Copy link
Member

aturon commented Jan 25, 2015

cc @sfackler @pythonesque -- I gave @steveklabnik an initial round of feedback, but there's still plenty of room for improvement here. I'm ok to land this as-is and improve though follow-up PRs, but if either of you have some time to help @steveklabnik iterate on it before landing, that would be great.

Some possible further improvements:

  1. Greater clarity about exactly which concurrency pitfalls Rust helps you with (memory safety, ownership protocols, data races) and which ones it doesn't (race conditions in general). A lot of uses of the word "safe" in the current writeup are somewhat vague. Explaining exactly what a data race is would help.
  2. More clarity and more concrete examples for Send and Sync.
  3. A bit more top-down explanation of Arc and Mutex; contrasting to Rc would be especially useful. It would help to be more clear that Arc doesn't assume lack of mutability per se -- rather, it only gives you a shared reference, which in the most basic form doesn't permit mutation. But the key here is "interior mutability" which is what Mutex is providing. Some of those concepts are implicit in the text, but I think it could be brought out more clearly.
  4. It's probably worth mentioning that the std::sync module provides all all the basic tools for communication and synchronization between threads -- you could even give a brief rundown, as a starting point for people wanting to dig deeper.

use std::time::Duration;

fn main() {
let data = Arc::new(Mutex::new(0u32));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit confusing that the type of data is changed from Vec<u32> to u32 here. The code should be consistent with previous examples.

Also if you want to keep Vec<u32>, the range must be written as 0us .. 2 otherwise you get the following error:

error: the trait `core::ops::IndexMut<i32>` is not implemented 
       for the type `collections::vec::Vec<u32>` [E0277]

Typos asides, nice work! :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for consistently with earlier examples.

I was also confused as to why, when the doc zeroes in on marker::NoSend as the big problem, the next sentence presents Arc as the solution. It seems to me like the proximal solution was to move data.lock().unwrap() inside the thread, so that the guard is not sent into the closure. I guess Arc is somehow necessary to move that line inside the closure, but the mechanism isn't clear.

I think the pedagogical approach of showing a series of failed attempts is very useful. Perhaps this section could benefit from adding yet another failed attempt to show the problem with moving data.lock.unwrap() inside the closure without Arc. After that we would see the final Arc example. That structure would be more precise about the problem Arc solves.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this could probably be improved. In the interest of actually landing this, I think doing that is worth waiting for, when we can address things like #21152 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(the consistency part will be improved, I meant more the NoSend bit

```

We now call `clone()` on our `Arc`, which increases the reference count. This
reference is then moved into the new thread. Let's examine the body of the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be confusing to use reference here, since a "reference" is & in Rust.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switched to 'internal,' what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand what you mean. ("This internal is then moved into the ..."??)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, i edied the previous line, 'increase the internal count' 😓

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we went with 'handle'

@steveklabnik
Copy link
Member Author

@huonw thanks for the feedback. i incorporated it all 👍

@steveklabnik steveklabnik force-pushed the tasks branch 2 times, most recently from 52f47d6 to 87da44a Compare February 2, 2015 11:40
@aturon
Copy link
Member

aturon commented Feb 2, 2015

(BTW, basically r=me after my last look at this, so send it on to bors once @huonw is happy)

@huonw
Copy link
Member

huonw commented Feb 4, 2015

@bors r+ 87da


Specifically, `F`, the closure that we pass to execute in the new thread. It
has two restrictions: It must be a `FnOnce` from `()` to `T`. Using `FnOnce`
allows the clousre to take ownership of any data it mentions from the parent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/clousre/closure/

@bors
Copy link
Collaborator

bors commented Feb 4, 2015

⌛ Testing commit 87da44a with merge 852a2f2...

@bors
Copy link
Collaborator

bors commented Feb 4, 2015

💔 Test failed - auto-win-32-nopt-t

@steveklabnik
Copy link
Member Author

I don't know how to fix this error, any ideas?

fn main() {
let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));

for i in (0us..10) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I this supposed to iterate up to 10? The length of the array is only 3. (this is causing the panic in the doc test and then windows may not be dealing with the panic-during-shutdown and aborting the process).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh ugh. thanks

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder why i didn't catch this when i ran my own tests

@steveklabnik
Copy link
Member Author

I have fixed this locally but this wifi blocks the ssh protocol, so I cannot upload it until tonight.

@steveklabnik
Copy link
Member Author

@bors: r=huonw 5401f08

@bors
Copy link
Collaborator

bors commented Feb 5, 2015

⌛ Testing commit 5401f08 with merge fa28f02...

bors added a commit that referenced this pull request Feb 5, 2015
This moves the "Tasks" chapter to a "Concurrency" one, as it's about threads, but also about how to deal with concurrency issues.

r? @aturon
@tomjakubowski
Copy link
Contributor

@steveklabnik for future reference, this may help push things to GitHub around SSH blocks: https://help.github.com/articles/using-ssh-over-the-https-port/

@steveklabnik
Copy link
Member Author

steveklabnik commented Feb 5, 2015 via email

@bors bors merged commit 5401f08 into rust-lang:master Feb 5, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.