From b8ffad5964e328340de0c03779577eb14caa16fc Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 26 Dec 2014 16:04:27 -0500 Subject: [PATCH] s/task/thread/g A part of #20038 --- src/doc/guide-tasks.md | 112 +++++++++++++++--------------- src/doc/guide.md | 58 ++++++++-------- src/doc/index.md | 2 +- src/doc/reference.md | 105 ++++++++++++++-------------- src/liballoc/rc.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/libstd/rand/mod.rs | 2 +- src/libstd/rt/mod.rs | 6 +- src/libstd/rt/task.rs | 130 +++++++++++++++++------------------ src/libstd/rt/unwind.rs | 22 +++--- src/libstd/sync/task_pool.rs | 32 ++++----- 11 files changed, 233 insertions(+), 240 deletions(-) diff --git a/src/doc/guide-tasks.md b/src/doc/guide-tasks.md index 87a3abd8f22..29c98e22ee9 100644 --- a/src/doc/guide-tasks.md +++ b/src/doc/guide-tasks.md @@ -1,6 +1,6 @@ -% The Rust Tasks and Communication Guide +% The Rust Threads and Communication Guide -**NOTE** This guide is badly out of date an needs to be rewritten. +**NOTE** This guide is badly out of date and needs to be rewritten. # Introduction @@ -9,36 +9,36 @@ primitives. This guide will describe the concurrency model in Rust, how it relates to the Rust type system, and introduce the fundamental library abstractions for constructing concurrent programs. -Tasks provide failure isolation and recovery. When a fatal error occurs in Rust +Threads provide failure isolation and recovery. When a fatal error occurs in Rust code as a result of an explicit call to `panic!()`, an assertion failure, or -another invalid operation, the runtime system destroys the entire task. Unlike +another invalid operation, the runtime system destroys the entire thread. Unlike in languages such as Java and C++, there is no way to `catch` an exception. -Instead, tasks may monitor each other to see if they panic. +Instead, threads may monitor each other to see if they panic. -Tasks use Rust's type system to provide strong memory safety guarantees. In -particular, the type system guarantees that tasks cannot induce a data race +Threads use Rust's type system to provide strong memory safety guarantees. In +particular, the type system guarantees that threads cannot induce a data race from shared mutable state. # Basics -At its simplest, creating a task is a matter of calling the `spawn` function -with a closure argument. `spawn` executes the closure in the new task. +At its simplest, creating a thread is a matter of calling the `spawn` function +with a closure argument. `spawn` executes the closure in the new thread. ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; -// Print something profound in a different task using a named function -fn print_message() { println!("I am running in a different task!"); } +// Print something profound in a different thread using a named function +fn print_message() { println!("I am running in a different thread!"); } spawn(print_message); // Alternatively, use a `move ||` expression instead of a named function. // `||` expressions evaluate to an unnamed closure. The `move` keyword // indicates that the closure should take ownership of any variables it // touches. -spawn(move || println!("I am also running in a different task!")); +spawn(move || println!("I am also running in a different thread!")); ``` -In Rust, a task is not a concept that appears in the language semantics. +In Rust, a thread is not a concept that appears in the language semantics. Instead, Rust's type system provides all the tools necessary to implement safe concurrency: particularly, ownership. The language leaves the implementation details to the standard library. @@ -49,26 +49,26 @@ argument a closure (of type `F`) that it will run exactly once. This closure is limited to capturing `Send`-able data from its environment (that is, data which is deeply owned). Limiting the closure to `Send` ensures that `spawn` can safely move the entire closure and all its -associated state into an entirely different task for execution. +associated state into an entirely different thread for execution. ```{rust,ignore} -# use std::task::spawn; -# fn generate_task_number() -> int { 0 } +# use std::thread::spawn; +# fn generate_thread_number() -> int { 0 } // Generate some state locally -let child_task_number = generate_task_number(); +let child_thread_number = generate_thread_number(); spawn(move || { - // Capture it in the remote task. The `move` keyword indicates - // that this closure should move `child_task_number` into its + // Capture it in the remote thread. The `move` keyword indicates + // that this closure should move `child_thread_number` into its // environment, rather than capturing a reference into the // enclosing stack frame. - println!("I am child number {}", child_task_number); + println!("I am child number {}", child_thread_number); }); ``` ## Communication -Now that we have spawned a new task, it would be nice if we could communicate +Now that we have spawned a new thread, it would be nice if we could communicate with it. For this, we use *channels*. A channel is simply a pair of endpoints: one for sending messages and another for receiving messages. @@ -78,7 +78,7 @@ of a channel, and a **receiver** is the receiving endpoint. Consider the followi example of calculating two results concurrently: ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; let (tx, rx): (Sender, Receiver) = channel(); @@ -102,12 +102,12 @@ into its component parts). let (tx, rx): (Sender, Receiver) = channel(); ``` -The child task will use the sender to send data to the parent task, which will +The child thread will use the sender to send data to the parent thread, which will wait to receive the data on the receiver. The next statement spawns the child -task. +thread. ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; # fn some_expensive_computation() -> int { 42 } # let (tx, rx) = channel(); spawn(move || { @@ -116,10 +116,10 @@ spawn(move || { }); ``` -Notice that the creation of the task closure transfers `tx` to the child task +Notice that the creation of the thread closure transfers `tx` to the child thread implicitly: the closure captures `tx` in its environment. Both `Sender` and -`Receiver` are sendable types and may be captured into tasks or otherwise -transferred between them. In the example, the child task runs an expensive +`Receiver` are sendable types and may be captured into threads or otherwise +transferred between them. In the example, the child thread runs an expensive computation, then sends the result over the captured channel. Finally, the parent continues with some other expensive computation, then waits @@ -137,7 +137,7 @@ The `Sender` and `Receiver` pair created by `channel` enables efficient communication between a single sender and a single receiver, but multiple senders cannot use a single `Sender` value, and multiple receivers cannot use a single `Receiver` value. What if our example needed to compute multiple -results across a number of tasks? The following program is ill-typed: +results across a number of threads? The following program is ill-typed: ```{rust,ignore} # fn some_expensive_computation() -> int { 42 } @@ -160,7 +160,7 @@ Instead we can clone the `tx`, which allows for multiple senders. let (tx, rx) = channel(); for init_val in range(0u, 3) { - // Create a new channel handle to distribute to the child task + // Create a new channel handle to distribute to the child thread let child_tx = tx.clone(); spawn(move || { child_tx.send(some_expensive_computation(init_val)); @@ -172,7 +172,7 @@ let result = rx.recv() + rx.recv() + rx.recv(); ``` Cloning a `Sender` produces a new handle to the same channel, allowing multiple -tasks to send data to a single receiver. It upgrades the channel internally in +threads to send data to a single receiver. It upgrades the channel internally in order to allow this functionality, which means that channels that are not cloned can avoid the overhead required to handle multiple senders. But this fact has no bearing on the channel's usage: the upgrade is transparent. @@ -182,9 +182,9 @@ simply use three `Sender` pairs, but it serves to illustrate the point. For reference, written with multiple streams, it might look like the example below. ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; -// Create a vector of ports, one for each child task +// Create a vector of ports, one for each child thread let rxs = Vec::from_fn(3, |init_val| { let (tx, rx) = channel(); spawn(move || { @@ -256,18 +256,18 @@ fn main() { ## Sharing without copying: Arc -To share data between tasks, a first approach would be to only use channel as +To share data between threads, a first approach would be to only use channel as we have seen previously. A copy of the data to share would then be made for -each task. In some cases, this would add up to a significant amount of wasted +each thread. In some cases, this would add up to a significant amount of wasted memory and would require copying the same data more than necessary. To tackle this issue, one can use an Atomically Reference Counted wrapper (`Arc`) as implemented in the `sync` library of Rust. With an Arc, the data -will no longer be copied for each task. The Arc acts as a reference to the +will no longer be copied for each thread. The Arc acts as a reference to the shared data and only this reference is shared and cloned. Here is a small example showing how to use Arcs. We wish to run concurrently -several computations on a single large vector of floats. Each task needs the +several computations on a single large vector of floats. Each thread needs the full vector to perform its duty. ```{rust,ignore} @@ -284,10 +284,10 @@ fn main() { let numbers_arc = Arc::new(numbers); for num in range(1u, 10) { - let task_numbers = numbers_arc.clone(); + let thread_numbers = numbers_arc.clone(); spawn(move || { - println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num)); + println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num)); }); } } @@ -306,8 +306,8 @@ let numbers_arc = Arc::new(numbers); # } ``` -and a clone is captured for each task via a procedure. This only copies -the wrapper and not its contents. Within the task's procedure, the captured +and a clone is captured for each thread via a procedure. This only copies +the wrapper and not its contents. Within the thread's procedure, the captured Arc reference can be used as a shared reference to the underlying vector as if it were local. @@ -319,29 +319,29 @@ if it were local. # let numbers=Vec::from_fn(1000000, |_| rand::random::()); # let numbers_arc = Arc::new(numbers); # let num = 4; -let task_numbers = numbers_arc.clone(); +let thread_numbers = numbers_arc.clone(); spawn(move || { - // Capture task_numbers and use it as if it was the underlying vector - println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num)); + // Capture thread_numbers and use it as if it was the underlying vector + println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num)); }); # } ``` -# Handling task panics +# Handling thread panics Rust has a built-in mechanism for raising exceptions. The `panic!()` macro (which can also be written with an error string as an argument: `panic!( ~reason)`) and the `assert!` construct (which effectively calls `panic!()` if a -boolean expression is false) are both ways to raise exceptions. When a task -raises an exception, the task unwinds its stack—running destructors and +boolean expression is false) are both ways to raise exceptions. When a thread +raises an exception, the thread unwinds its stack—running destructors and freeing memory along the way—and then exits. Unlike exceptions in C++, -exceptions in Rust are unrecoverable within a single task: once a task panics, +exceptions in Rust are unrecoverable within a single thread: once a thread panics, there is no way to "catch" the exception. -While it isn't possible for a task to recover from panicking, tasks may notify +While it isn't possible for a thread to recover from panicking, threads may notify each other if they panic. The simplest way of handling a panic is with the `try` function, which is similar to `spawn`, but immediately blocks and waits -for the child task to finish. `try` returns a value of type +for the child thread to finish. `try` returns a value of type `Result>`. `Result` is an `enum` type with two variants: `Ok` and `Err`. In this case, because the type arguments to `Result` are `int` and `()`, callers can pattern-match on a result to check whether it's an `Ok` @@ -364,14 +364,14 @@ assert!(result.is_err()); Unlike `spawn`, the function spawned using `try` may return a value, which `try` will dutifully propagate back to the caller in a [`Result`] enum. If the -child task terminates successfully, `try` will return an `Ok` result; if the -child task panics, `try` will return an `Error` result. +child thread terminates successfully, `try` will return an `Ok` result; if the +child thread panics, `try` will return an `Error` result. [`Result`]: std/result/index.html -> *Note:* A panicked task does not currently produce a useful error +> *Note:* A panicked thread does not currently produce a useful error > value (`try` always returns `Err(())`). In the -> future, it may be possible for tasks to intercept the value passed to +> future, it may be possible for threads to intercept the value passed to > `panic!()`. But not all panics are created equal. In some cases you might need to abort @@ -379,4 +379,4 @@ the entire program (perhaps you're writing an assert which, if it trips, indicates an unrecoverable logic error); in other cases you might want to contain the panic at a certain boundary (perhaps a small piece of input from the outside world, which you happen to be processing in parallel, is malformed -such that the processing task cannot proceed). +such that the processing thread cannot proceed). diff --git a/src/doc/guide.md b/src/doc/guide.md index 22cbd18a865..7d1558465a1 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -3036,7 +3036,7 @@ test foo ... FAILED failures: ---- foo stdout ---- - task 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 + thread 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 @@ -3045,7 +3045,7 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured -task '
' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 +thread '
' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 ``` Lots of output! Let's break this down: @@ -3088,7 +3088,7 @@ failed, especially as we accumulate more tests. failures: ---- foo stdout ---- - task 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 + thread 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 @@ -3097,7 +3097,7 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured -task '
' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 +thread '
' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 ``` After all the tests run, Rust will show us any output from our failed tests. @@ -4263,7 +4263,7 @@ is that a moving closure always takes ownership of all variables that it uses. Ordinary closures, in contrast, just create a reference into the enclosing stack frame. Moving closures are most useful with Rust's concurrency features, and so we'll just leave it at this for -now. We'll talk about them more in the "Tasks" section of the guide. +now. We'll talk about them more in the "Threads" section of the guide. ## Accepting closures as arguments @@ -5213,9 +5213,7 @@ as you can see, there's no overhead of deciding which version to call here, hence 'statically dispatched'. The downside is that we have two copies of the same function, so our binary is a little bit larger. -# Tasks - -**NOTE**: this section is currently out of date and will be rewritten soon. +# Threads Concurrency and parallelism are topics that are of increasing interest to a broad subsection of software developers. Modern computers are often multi-core, @@ -5224,24 +5222,22 @@ processor. Rust's semantics lend themselves very nicely to solving a number of issues that programmers have with concurrency. Many concurrency errors that are runtime errors in other languages are compile-time errors in Rust. -Rust's concurrency primitive is called a **task**. Tasks are similar to -threads, and do not share memory in an unsafe manner, preferring message -passing to communicate. It's worth noting that tasks are implemented as a -library, and not part of the language. This means that in the future, other -concurrency libraries can be written for Rust to help in specific scenarios. -Here's an example of creating a task: +Rust's concurrency primitive is called a **thread**. It's worth noting that +threads are implemented as a library, and not part of the language. This means +that in the future, other concurrency libraries can be written for Rust to help +in specific scenarios. Here's an example of creating a thread: ```{rust,ignore} spawn(move || { - println!("Hello from a task!"); + println!("Hello from a thread!"); }); ``` The `spawn` function takes a closure as an argument, and runs that -closure in a new task. Typically, you will want to use a moving +closure in a new thread. Typically, you will want to use a moving closure, so that the closure takes ownership of any variables that it touches. This implies that those variables are not usable from the -parent task after the child task is spawned: +parent thread after the child thread is spawned: ```{rust,ignore} let mut x = vec![1i, 2i, 3i]; @@ -5257,15 +5253,15 @@ println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x` other languages would let us do this, but it's not safe to do so. Rust's borrow checker catches the error. -If tasks were only able to capture these values, they wouldn't be very useful. -Luckily, tasks can communicate with each other through **channel**s. Channels +If threads were only able to capture these values, they wouldn't be very useful. +Luckily, threads can communicate with each other through **channel**s. Channels work like this: ```{rust,ignore} let (tx, rx) = channel(); spawn(move || { - tx.send("Hello from a task!".to_string()); + tx.send("Hello from a thread!".to_string()); }); let message = rx.recv(); @@ -5278,14 +5274,14 @@ receive the message on the `Receiver` side with the `recv()` method. This method blocks until it gets a message. There's a similar method, `.try_recv()`, which returns an `Result` and does not block. -If you want to send messages to the task as well, create two channels! +If you want to send messages to the thread as well, create two channels! ```{rust,ignore} let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); spawn(move || { - tx1.send("Hello from a task!".to_string()); + tx1.send("Hello from a thread!".to_string()); let message = rx2.recv(); println!("{}", message); }); @@ -5296,9 +5292,9 @@ println!("{}", message); tx2.send("Goodbye from main!".to_string()); ``` -The closure has one sending end and one receiving end, and the main -task has one of each as well. Now they can talk back and forth in -whatever way they wish. +The closure has one sending end and one receiving end, and the main thread has +one of each as well. Now they can talk back and forth in whatever way they +wish. Notice as well that because `Sender` and `Receiver` are generic, while you can pass any kind of information through the channel, the ends are strongly typed. @@ -5337,7 +5333,7 @@ we'll just get the value immediately. ## Success and failure -Tasks don't always succeed, they can also panic. A task that wishes to panic +Threads don't always succeed, they can also panic. A thread that wishes to panic can call the `panic!` macro, passing a message: ```{rust,ignore} @@ -5346,14 +5342,14 @@ spawn(move || { }); ``` -If a task panics, it is not possible for it to recover. However, it can -notify other tasks that it has panicked. We can do this with `task::try`: +If a thread panics, it is not possible for it to recover. However, it can +notify other thread that it has panicked. We can do this with `thread::try`: ```{rust,ignore} -use std::task; +use std::thread; use std::rand; -let result = task::try(move || { +let result = thread::try(move || { if rand::random() { println!("OK"); } else { @@ -5362,7 +5358,7 @@ let result = task::try(move || { }); ``` -This task will randomly panic or succeed. `task::try` returns a `Result` +This thread will randomly panic or succeed. `thread::try` returns a `Result` type, so we can handle the response like any other computation that may fail. diff --git a/src/doc/index.md b/src/doc/index.md index 77909955822..e54bf0eb242 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -58,7 +58,7 @@ a guide that can help you out: * [Strings](guide-strings.html) * [Pointers](guide-pointers.html) * [Crates and modules](guide-crates.html) -* [Tasks and Communication](guide-tasks.html) +* [Threads and Communication](guide-threads.html) * [Error Handling](guide-error-handling.html) * [Foreign Function Interface](guide-ffi.html) * [Writing Unsafe and Low-Level Code](guide-unsafe.html) diff --git a/src/doc/reference.md b/src/doc/reference.md index 97184d53498..7c770063fe6 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -899,8 +899,8 @@ mirrors the module hierarchy. // Load the `vec` module from `vec.rs` mod vec; -mod task { - // Load the `local_data` module from `task/local_data.rs` +mod thread { + // Load the `local_data` module from `thread/local_data.rs` mod local_data; } ``` @@ -909,9 +909,9 @@ The directories and files used for loading external file modules can be influenced with the `path` attribute. ```{.ignore} -#[path = "task_files"] -mod task { - // Load the `local_data` module from `task_files/tls.rs` +#[path = "thread_files"] +mod thread { + // Load the `local_data` module from `thread_files/tls.rs` #[path = "tls.rs"] mod local_data; } @@ -1188,7 +1188,7 @@ code safe, in the surrounding context. Unsafe blocks are used to wrap foreign libraries, make direct use of hardware or implement features not directly present in the language. For example, Rust provides the language features necessary to implement memory-safe concurrency -in the language but the implementation of tasks and message passing is in the +in the language but the implementation of threads and message passing is in the standard library. Rust's type system is a conservative approximation of the dynamic safety @@ -1500,7 +1500,7 @@ be modified by the program. One of Rust's goals is to make concurrency bugs hard to run into, and this is obviously a very large source of race conditions or other bugs. For this reason, an `unsafe` block is required when either reading or writing a mutable static variable. Care should be taken to ensure -that modifications to a mutable static are safe with respect to other tasks +that modifications to a mutable static are safe with respect to other threads running in the same process. Mutable statics are still very useful, however. They can be used with C @@ -2253,11 +2253,11 @@ A complete list of the built-in language items follows: * `drop` : Have destructors. * `send` - : Able to be sent across task boundaries. + : Able to be sent across thread boundaries. * `sized` : Has a size known at compile time. * `sync` - : Able to be safely shared between tasks when aliased. + : Able to be safely shared between threads when aliased. #### Operators @@ -2621,7 +2621,7 @@ The currently implemented features of the reference compiler are: LLVM's implementation which works in concert with the kernel loader and dynamic linker. This is not necessarily available on all platforms, and usage of it is discouraged (rust - focuses more on task-local data instead of thread-local + focuses more on thread-local data instead of thread-local data). * `trace_macros` - Allows use of the `trace_macros` macro, which is a nasty @@ -2939,7 +2939,7 @@ array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to. Indices are zero-based, and may be of any integral type. Vector access is -bounds-checked at run-time. When the check fails, it will put the task in a +bounds-checked at run-time. When the check fails, it will put the thread in a _panicked state_. ```{should-fail} @@ -3950,7 +3950,7 @@ Types in Rust are categorized into kinds, based on various properties of the components of the type. The kinds are: * `Send` - : Types of this kind can be safely sent between tasks. + : Types of this kind can be safely sent between threads. This kind includes scalars, boxes, procs, and structural types containing only other owned types. All `Send` types are `'static`. @@ -3998,21 +3998,21 @@ to sendable. # Memory and concurrency models -Rust has a memory model centered around concurrently-executing _tasks_. Thus +Rust has a memory model centered around concurrently-executing _threads_. Thus its memory model and its concurrency model are best discussed simultaneously, as parts of each only make sense when considered from the perspective of the other. When reading about the memory model, keep in mind that it is partitioned in -order to support tasks; and when reading about tasks, keep in mind that their +order to support threads; and when reading about threads, keep in mind that their isolation and communication mechanisms are only possible due to the ownership and lifetime semantics of the memory model. ## Memory model A Rust program's memory consists of a static set of *items*, a set of -[tasks](#tasks) each with its own *stack*, and a *heap*. Immutable portions of -the heap may be shared between tasks, mutable portions may not. +[threads](#threads) each with its own *stack*, and a *heap*. Immutable portions of +the heap may be shared between threads, mutable portions may not. Allocations in the stack consist of *slots*, and allocations in the heap consist of *boxes*. @@ -4023,8 +4023,8 @@ The _items_ of a program are those functions, modules and types that have their value calculated at compile-time and stored uniquely in the memory image of the rust process. Items are neither dynamically allocated nor freed. -A task's _stack_ consists of activation frames automatically allocated on entry -to each function as the task executes. A stack allocation is reclaimed when +A thread's _stack_ consists of activation frames automatically allocated on entry +to each function as the thread executes. A stack allocation is reclaimed when control leaves the frame containing it. The _heap_ is a general term that describes boxes. The lifetime of an @@ -4034,10 +4034,10 @@ in the heap, heap allocations may outlive the frame they are allocated within. ### Memory ownership -A task owns all memory it can *safely* reach through local variables, as well +A thread owns all memory it can *safely* reach through local variables, as well as boxes and references. -When a task sends a value that has the `Send` trait to another task, it loses +When a thread sends a value that has the `Send` trait to another thread, it loses ownership of the value sent and can no longer refer to it. This is statically guaranteed by the combined use of "move semantics", and the compiler-checked _meaning_ of the `Send` trait: it is only instantiated for (transitively) @@ -4046,12 +4046,12 @@ sendable kinds of data constructor and pointers, never including references. When a stack frame is exited, its local allocations are all released, and its references to boxes are dropped. -When a task finishes, its stack is necessarily empty and it therefore has no +When a thread finishes, its stack is necessarily empty and it therefore has no references to any boxes; the remainder of its heap is immediately freed. ### Memory slots -A task's stack contains slots. +A thread's stack contains slots. A _slot_ is a component of a stack frame, either a function parameter, a [temporary](#lvalues,-rvalues-and-temporaries), or a local variable. @@ -4105,72 +4105,69 @@ let y = x; // attempting to use `x` will result in an error here ``` -## Tasks +## Threads -An executing Rust program consists of a tree of tasks. A Rust _task_ consists -of an entry function, a stack, a set of outgoing communication channels and -incoming communication ports, and ownership of some portion of the heap of a -single operating-system process. +Rust's primary concurrency mechanism is called a **thread**. -### Communication between tasks +### Communication between threads -Rust tasks are isolated and generally unable to interfere with one another's +Rust threads are isolated and generally unable to interfere with one another's memory directly, except through [`unsafe` code](#unsafe-functions). All -contact between tasks is mediated by safe forms of ownership transfer, and data +contact between threads is mediated by safe forms of ownership transfer, and data races on memory are prohibited by the type system. -When you wish to send data between tasks, the values are restricted to the +When you wish to send data between threads, the values are restricted to the [`Send` type-kind](#type-kinds). Restricting communication interfaces to this -kind ensures that no references move between tasks. Thus access to an entire +kind ensures that no references move between threads. Thus access to an entire data structure can be mediated through its owning "root" value; no further locking or copying is required to avoid data races within the substructure of such a value. -### Task lifecycle +### Thread -The _lifecycle_ of a task consists of a finite set of states and events that -cause transitions between the states. The lifecycle states of a task are: +The _lifecycle_ of a threads consists of a finite set of states and events that +cause transitions between the states. The lifecycle states of a thread are: * running * blocked * panicked * dead -A task begins its lifecycle — once it has been spawned — in the +A thread begins its lifecycle — once it has been spawned — in the *running* state. In this state it executes the statements of its entry function, and any functions called by the entry function. -A task may transition from the *running* state to the *blocked* state any time +A thread may transition from the *running* state to the *blocked* state any time it makes a blocking communication call. When the call can be completed — when a message arrives at a sender, or a buffer opens to receive a message -— then the blocked task will unblock and transition back to *running*. +— then the blocked thread will unblock and transition back to *running*. -A task may transition to the *panicked* state at any time, due being killed by +A thread may transition to the *panicked* state at any time, due being killed by some external event or internally, from the evaluation of a `panic!()` macro. -Once *panicking*, a task unwinds its stack and transitions to the *dead* state. -Unwinding the stack of a task is done by the task itself, on its own control +Once *panicking*, a thread unwinds its stack and transitions to the *dead* state. +Unwinding the stack of a thread is done by the thread itself, on its own control stack. If a value with a destructor is freed during unwinding, the code for the -destructor is run, also on the task's control stack. Running the destructor +destructor is run, also on the thread's control stack. Running the destructor code causes a temporary transition to a *running* state, and allows the -destructor code to cause any subsequent state transitions. The original task +destructor code to cause any subsequent state transitions. The original thread of unwinding and panicking thereby may suspend temporarily, and may involve (recursive) unwinding of the stack of a failed destructor. Nonetheless, the outermost unwinding activity will continue until the stack is unwound and the -task transitions to the *dead* state. There is no way to "recover" from task -panics. Once a task has temporarily suspended its unwinding in the *panicking* +thread transitions to the *dead* state. There is no way to "recover" from thread +panics. Once a thread has temporarily suspended its unwinding in the *panicking* state, a panic occurring from within this destructor results in *hard* panic. A hard panic currently results in the process aborting. -A task in the *dead* state cannot transition to other states; it exists only to -have its termination status inspected by other tasks, and/or to await +A thread in the *dead* state cannot transition to other states; it exists only to +have its termination status inspected by other threads, and/or to await reclamation when the last reference to it drops. # Runtime services, linkage and debugging The Rust _runtime_ is a relatively compact collection of Rust code that -provides fundamental services and datatypes to all Rust tasks at run-time. It +provides fundamental services and datatypes to all Rust threads at run-time. It is smaller and simpler than many modern language runtimes. It is tightly -integrated into the language's execution model of memory, tasks, communication +integrated into the language's execution model of memory, threads, communication and logging. ### Memory allocation @@ -4181,7 +4178,7 @@ environment and releases them back to its environment when they are no longer needed. The default implementation of the service-provider interface consists of the C runtime functions `malloc` and `free`. -The runtime memory-management system, in turn, supplies Rust tasks with +The runtime memory-management system, in turn, supplies Rust threads with facilities for allocating releasing stacks, as well as allocating and freeing heap data. @@ -4189,15 +4186,15 @@ heap data. The runtime provides C and Rust code to assist with various built-in types, such as arrays, strings, and the low level communication system (ports, -channels, tasks). +channels, threads). Support for other built-in types such as simple types, tuples and enums is open-coded by the Rust compiler. -### Task scheduling and communication +### Thread scheduling and communication -The runtime provides code to manage inter-task communication. This includes -the system of task-lifecycle state transitions depending on the contents of +The runtime provides code to manage inter-thread communication. This includes +the system of thread-lifecycle state transitions depending on the contents of queues, as well as code to copy values between queues and their recipients and to serialize values for transmission over operating-system inter-process communication facilities. diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index dfa55848c90..e927cb72a13 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Task-local reference-counted boxes (the `Rc` type). +//! Thread-local reference-counted boxes (the `Rc` type). //! //! The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, //! and will occur as soon as the last owner is gone. It is marked as non-sendable because it diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e2791aff14e..e20404bf638 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -540,7 +540,7 @@ pub fn monitor(f: F) { match cfg.spawn(move || { std::io::stdio::set_stderr(box w); f() }).join() { Ok(()) => { /* fallthrough */ } Err(value) => { - // Task panicked without emitting a fatal diagnostic + // Thread panicked without emitting a fatal diagnostic if !value.is::() { let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index c590c0f575e..292f3e056dd 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -18,7 +18,7 @@ //! See the `distributions` submodule for sampling random numbers from //! distributions like normal and exponential. //! -//! # Task-local RNG +//! # Thread-local RNG //! //! There is built-in support for a RNG associated with each task stored //! in task-local storage. This RNG can be accessed via `task_rng`, or diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index d64336569c6..e877dd5c6aa 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -53,7 +53,7 @@ pub mod args; mod at_exit_imp; mod libunwind; -/// The default error code of the rust runtime if the main task panics instead +/// The default error code of the rust runtime if the main thread panics instead /// of exiting cleanly. pub const DEFAULT_ERROR_CODE: int = 101; @@ -137,9 +137,9 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { /// /// The procedure passed to this function will be executed as part of the /// runtime cleanup phase. For normal rust programs, this means that it will run -/// after all other tasks have exited. +/// after all other threads have exited. /// -/// The procedure is *not* executed with a local `Task` available to it, so +/// The procedure is *not* executed with a local `Thread` available to it, so /// primitives like logging, I/O, channels, spawning, etc, are *not* available. /// This is meant for "bare bones" usage to clean up runtime details, this is /// not meant as a general-purpose "let's clean everything up" function. diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 98940a2b381..773322e4f57 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -36,7 +36,7 @@ use sys_common::stack; use rt::unwind; use rt::unwind::Unwinder; -/// State associated with Rust tasks. +/// State associated with Rust threads /// /// This structure is currently undergoing major changes, and is /// likely to be move/be merged with a `Thread` structure. @@ -50,14 +50,14 @@ pub struct Task { awoken: bool, // used to prevent spurious wakeups // This field holds the known bounds of the stack in (lo, hi) form. Not all - // native tasks necessarily know their precise bounds, hence this is + // native threads necessarily know their precise bounds, hence this is // optional. stack_bounds: (uint, uint), stack_guard: uint } -// Once a task has entered the `Armed` state it must be destroyed via `drop`, +// Once a thread has entered the `Armed` state it must be destroyed via `drop`, // and no other method. This state is used to track this transition. #[deriving(PartialEq)] enum TaskState { @@ -67,31 +67,31 @@ enum TaskState { } pub struct TaskOpts { - /// Invoke this procedure with the result of the task when it finishes. + /// Invoke this procedure with the result of the thread when it finishes. pub on_exit: Option>, - /// A name for the task-to-be, for identification in panic messages + /// A name for the thread-to-be, for identification in panic messages pub name: Option, - /// The size of the stack for the spawned task + /// The size of the stack for the spawned thread pub stack_size: Option, } -/// Indicates the manner in which a task exited. +/// Indicates the manner in which a thread exited. /// -/// A task that completes without panicking is considered to exit successfully. +/// A thread that completes without panicking is considered to exit successfully. /// /// If you wish for this result's delivery to block until all -/// children tasks complete, recommend using a result future. +/// children threads complete, recommend using a result future. pub type Result = ::core::result::Result<(), Box>; -/// A handle to a blocked task. Usually this means having the Box -/// pointer by ownership, but if the task is killable, a killer can steal it +/// A handle to a blocked thread. Usually this means having the Box +/// pointer by ownership, but if the thread is killable, a killer can steal it /// at any time. pub enum BlockedTask { Owned(Box), Shared(Arc), } -/// Per-task state related to task death, killing, panic, etc. +/// Per-thread state related to thread death, killing, panic, etc. pub struct Death { pub on_exit: Option>, } @@ -101,7 +101,7 @@ pub struct BlockedTasks { } impl Task { - /// Creates a new uninitialized task. + /// Creates a new uninitialized thread. pub fn new(stack_bounds: Option<(uint, uint)>, stack_guard: Option) -> Task { Task { unwinder: Unwinder::new(), @@ -153,17 +153,17 @@ impl Task { }) } - /// Consumes ownership of a task, runs some code, and returns the task back. + /// Consumes ownership of a thread, runs some code, and returns the thread back. /// /// This function can be used as an emulated "try/catch" to interoperate /// with the rust runtime at the outermost boundary. It is not possible to /// use this function in a nested fashion (a try/catch inside of another /// try/catch). Invoking this function is quite cheap. /// - /// If the closure `f` succeeds, then the returned task can be used again + /// If the closure `f` succeeds, then the returned thread can be used again /// for another invocation of `run`. If the closure `f` panics then `self` /// will be internally destroyed along with all of the other associated - /// resources of this task. The `on_exit` callback is invoked with the + /// resources of this thread. The `on_exit` callback is invoked with the /// cause of panic (not returned here). This can be discovered by querying /// `is_destroyed()`. /// @@ -172,30 +172,30 @@ impl Task { /// guaranteed to return if it panicks. Care should be taken to ensure that /// stack references made by `f` are handled appropriately. /// - /// It is invalid to call this function with a task that has been previously + /// It is invalid to call this function with a thread that has been previously /// destroyed via a failed call to `run`. pub fn run(mut self: Box, f: ||) -> Box { - assert!(!self.is_destroyed(), "cannot re-use a destroyed task"); + assert!(!self.is_destroyed(), "cannot re-use a destroyed thread"); // First, make sure that no one else is in TLS. This does not allow // recursive invocations of run(). If there's no one else, then // relinquish ownership of ourselves back into TLS. if Local::exists(None::) { - panic!("cannot run a task recursively inside another"); + panic!("cannot run a thread recursively inside another"); } self.state = Armed; Local::put(self); // There are two primary reasons that general try/catch is unsafe. The // first is that we do not support nested try/catch. The above check for - // an existing task in TLS is sufficient for this invariant to be + // an existing thread in TLS is sufficient for this invariant to be // upheld. The second is that unwinding while unwinding is not defined. - // We take care of that by having an 'unwinding' flag in the task + // We take care of that by having an 'unwinding' flag in the thread // itself. For these reasons, this unsafety should be ok. let result = unsafe { unwind::try(f) }; - // After running the closure given return the task back out if it ran - // successfully, or clean up the task if it panicked. + // After running the closure given return the thread back out if it ran + // successfully, or clean up the thread if it panicked. let task: Box = Local::take(); match result { Ok(()) => task, @@ -203,13 +203,13 @@ impl Task { } } - /// Destroy all associated resources of this task. + /// Destroy all associated resources of this thread. /// - /// This function will perform any necessary clean up to prepare the task + /// This function will perform any necessary clean up to prepare the thread /// for destruction. It is required that this is called before a `Task` /// falls out of scope. /// - /// The returned task cannot be used for running any more code, but it may + /// The returned thread cannot be used for running any more code, but it may /// be used to extract the runtime as necessary. pub fn destroy(self: Box) -> Box { if self.is_destroyed() { @@ -219,14 +219,14 @@ impl Task { } } - /// Cleans up a task, processing the result of the task as appropriate. + /// Cleans up a thread, processing the result of the thread as appropriate. /// - /// This function consumes ownership of the task, deallocating it once it's + /// This function consumes ownership of the thread, deallocating it once it's /// done being processed. It is assumed that TLD and the local heap have /// already been destroyed and/or annihilated. fn cleanup(mut self: Box, result: Result) -> Box { // After taking care of the data above, we need to transmit the result - // of this task. + // of this thread. let what_to_do = self.death.on_exit.take(); Local::put(self); @@ -235,15 +235,15 @@ impl Task { // if this panics, this will also likely abort the runtime. // // This closure is currently limited to a channel send via the - // standard library's task interface, but this needs + // standard library's thread interface, but this needs // reconsideration to whether it's a reasonable thing to let a - // task to do or not. + // thread to do or not. match what_to_do { Some(f) => { f.invoke(result) } None => { drop(result) } } - // Now that we're done, we remove the task from TLS and flag it for + // Now that we're done, we remove the thread from TLS and flag it for // destruction. let mut task: Box = Local::take(); task.state = Destroyed; @@ -253,7 +253,7 @@ impl Task { /// Queries whether this can be destroyed or not. pub fn is_destroyed(&self) -> bool { self.state == Destroyed } - /// Deschedules the current task, invoking `f` `amt` times. It is not + /// Deschedules the current thread, invoking `f` `amt` times. It is not /// recommended to use this function directly, but rather communication /// primitives in `std::comm` should be used. // @@ -262,31 +262,31 @@ impl Task { // shared state. Additionally, all of the violations are protected with a // mutex, so in theory there are no races. // - // The first thing we need to do is to get a pointer to the task's internal - // mutex. This address will not be changing (because the task is allocated - // on the heap). We must have this handle separately because the task will + // The first thing we need to do is to get a pointer to the thread's internal + // mutex. This address will not be changing (because the thread is allocated + // on the heap). We must have this handle separately because the thread will // have its ownership transferred to the given closure. We're guaranteed, // however, that this memory will remain valid because *this* is the current - // task's execution thread. + // thread's execution thread. // - // The next weird part is where ownership of the task actually goes. We + // The next weird part is where ownership of the thread actually goes. We // relinquish it to the `f` blocking function, but upon returning this - // function needs to replace the task back in TLS. There is no communication - // from the wakeup thread back to this thread about the task pointer, and - // there's really no need to. In order to get around this, we cast the task + // function needs to replace the thread back in TLS. There is no communication + // from the wakeup thread back to this thread about the thread pointer, and + // there's really no need to. In order to get around this, we cast the thread // to a `uint` which is then used at the end of this function to cast back // to a `Box` object. Naturally, this looks like it violates // ownership semantics in that there may be two `Box` objects. // // The fun part is that the wakeup half of this implementation knows to - // "forget" the task on the other end. This means that the awakening half of + // "forget" the thread on the other end. This means that the awakening half of // things silently relinquishes ownership back to this thread, but not in a - // way that the compiler can understand. The task's memory is always valid - // for both tasks because these operations are all done inside of a mutex. + // way that the compiler can understand. The thread's memory is always valid + // for both threads because these operations are all done inside of a mutex. // // You'll also find that if blocking fails (the `f` function hands the // BlockedTask back to us), we will `mem::forget` the handles. The - // reasoning for this is the same logic as above in that the task silently + // reasoning for this is the same logic as above in that the thread silently // transfers ownership via the `uint`, not through normal compiler // semantics. // @@ -319,11 +319,11 @@ impl Task { let guard = (*me).lock.lock(); (*me).awoken = false; - // Apply the given closure to all of the "selectable tasks", + // Apply the given closure to all of the "selectable threads", // bailing on the first one that produces an error. Note that // care must be taken such that when an error is occurred, we - // may not own the task, so we may still have to wait for the - // task to become available. In other words, if task.wake() + // may not own the thread, so we may still have to wait for the + // thread to become available. In other words, if thread.wake() // returns `None`, then someone else has ownership and we must // wait for their signal. match iter.map(f).filter_map(|a| a.err()).next() { @@ -342,15 +342,15 @@ impl Task { guard.wait(); } } - // put the task back in TLS, and everything is as it once was. + // put the thread back in TLS, and everything is as it once was. Local::put(mem::transmute(me)); } } - /// Wakes up a previously blocked task. This function can only be - /// called on tasks that were previously blocked in `deschedule`. + /// Wakes up a previously blocked thread. This function can only be + /// called on threads that were previously blocked in `deschedule`. // - // See the comments on `deschedule` for why the task is forgotten here, and + // See the comments on `deschedule` for why the thread is forgotten here, and // why it's valid to do so. pub fn reawaken(mut self: Box) { unsafe { @@ -362,21 +362,21 @@ impl Task { } } - /// Yields control of this task to another task. This function will + /// Yields control of this thread to another thread. This function will /// eventually return, but possibly not immediately. This is used as an - /// opportunity to allow other tasks a chance to run. + /// opportunity to allow other threads a chance to run. pub fn yield_now() { Thread::yield_now(); } - /// Returns the stack bounds for this task in (lo, hi) format. The stack - /// bounds may not be known for all tasks, so the return value may be + /// Returns the stack bounds for this thread in (lo, hi) format. The stack + /// bounds may not be known for all threads, so the return value may be /// `None`. pub fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds } - /// Returns the stack guard for this task, if known. + /// Returns the stack guard for this thread, if known. pub fn stack_guard(&self) -> Option { if self.stack_guard != 0 { Some(self.stack_guard) @@ -385,9 +385,9 @@ impl Task { } } - /// Consume this task, flagging it as a candidate for destruction. + /// Consume this thread, flagging it as a candidate for destruction. /// - /// This function is required to be invoked to destroy a task. A task + /// This function is required to be invoked to destroy a thread. A thread /// destroyed through a normal drop will abort. pub fn drop(mut self) { self.state = Destroyed; @@ -396,7 +396,7 @@ impl Task { impl Drop for Task { fn drop(&mut self) { - rtdebug!("called drop for a task: {}", self as *mut Task as uint); + rtdebug!("called drop for a thread: {}", self as *mut Task as uint); rtassert!(self.state != Armed); } } @@ -414,7 +414,7 @@ impl Iterator for BlockedTasks { } impl BlockedTask { - /// Returns Some if the task was successfully woken; None if already killed. + /// Returns Some if the thread was successfully woken; None if already killed. pub fn wake(self) -> Option> { match self { Owned(task) => Some(task), @@ -427,7 +427,7 @@ impl BlockedTask { } } - /// Reawakens this task if ownership is acquired. If finer-grained control + /// Reawakens this thread if ownership is acquired. If finer-grained control /// is desired, use `wake` instead. pub fn reawaken(self) { self.wake().map(|t| t.reawaken()); @@ -438,12 +438,12 @@ impl BlockedTask { #[cfg(not(test))] pub fn trash(self) { } #[cfg(test)] pub fn trash(self) { assert!(self.wake().is_none()); } - /// Create a blocked task, unless the task was already killed. + /// Create a blocked thread, unless the thread was already killed. pub fn block(task: Box) -> BlockedTask { Owned(task) } - /// Converts one blocked task handle to a list of many handles to the same. + /// Converts one blocked thread handle to a list of many handles to the same. pub fn make_selectable(self, num_handles: uint) -> Take { let arc = match self { Owned(task) => { @@ -543,7 +543,7 @@ mod test { drop(Task::new(None, None)); } - // Task blocking tests + // Thread blocking tests #[test] fn block_and_wake() { diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index eb15a7ba378..4d57db9a929 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -79,7 +79,7 @@ struct Exception { pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: uint); -// Variables used for invoking callbacks when a task starts to unwind. +// Variables used for invoking callbacks when a thread starts to unwind. // // For more information, see below. const MAX_CALLBACKS: uint = 16; @@ -106,14 +106,14 @@ thread_local! { static PANICKING: Cell = Cell::new(false) } /// /// * This is not safe to call in a nested fashion. The unwinding /// interface for Rust is designed to have at most one try/catch block per -/// task, not multiple. No runtime checking is currently performed to uphold +/// thread, not multiple. No runtime checking is currently performed to uphold /// this invariant, so this function is not safe. A nested try/catch block /// may result in corruption of the outer try/catch block's state, especially -/// if this is used within a task itself. +/// if this is used within a thread itself. /// -/// * It is not sound to trigger unwinding while already unwinding. Rust tasks +/// * It is not sound to trigger unwinding while already unwinding. Rust threads /// have runtime checks in place to ensure this invariant, but it is not -/// guaranteed that a rust task is in place when invoking this function. +/// guaranteed that a rust thread is in place when invoking this function. /// Unwinding twice can lead to resource leaks where some destructors are not /// run. pub unsafe fn try(f: F) -> Result<(), Box> { @@ -203,7 +203,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { // _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase. // // This is pretty close to Rust's exception handling approach, except that Rust -// does have a single "catch-all" handler at the bottom of each task's stack. +// does have a single "catch-all" handler at the bottom of each thread's stack. // So we have two versions of the personality routine: // - rust_eh_personality, used by all cleanup landing pads, which never catches, // so the behavior of __gcc_personality_v0 is perfectly adequate there, and @@ -523,7 +523,7 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, uint)) -> // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If // we do start doing this, then we should propagate this allocation to - // be performed in the parent of this task instead of the task that's + // be performed in the parent of this thread instead of the thread that's // panicking. // see below for why we do the `Any` coercion here. @@ -546,7 +546,7 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> static INIT: Once = ONCE_INIT; INIT.doit(|| unsafe { register(failure::on_fail); }); - // First, invoke call the user-defined callbacks triggered on task panic. + // First, invoke call the user-defined callbacks triggered on thread panic. // // By the time that we see a callback has been registered (by reading // MAX_CALLBACKS), the actual callback itself may have not been stored yet, @@ -574,7 +574,7 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> // If a thread panics while it's already unwinding then we // have limited options. Currently our preference is to // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the task cleanly. + // unwinding or otherwise exiting the thread cleanly. rterrln!("thread panicked while panicking. aborting."); unsafe { intrinsics::abort() } } @@ -582,10 +582,10 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> rust_panic(msg); } -/// Register a callback to be invoked when a task unwinds. +/// Register a callback to be invoked when a thread unwinds. /// /// This is an unsafe and experimental API which allows for an arbitrary -/// callback to be invoked when a task panics. This callback is invoked on both +/// callback to be invoked when a thread panics. This callback is invoked on both /// the initial unwinding and a double unwinding if one occurs. Additionally, /// the local `Task` will be in place for the duration of the callback, and /// the callback must ensure that it remains in place once the callback returns. diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 366e4b7d35b..5fc02e7b316 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Abstraction of a task pool for basic parallelism. +//! Abstraction of a thread pool for basic parallelism. use core::prelude::*; @@ -45,9 +45,9 @@ impl<'a> Drop for Sentinel<'a> { } } -/// A task pool used to execute functions in parallel. +/// A thread pool used to execute functions in parallel. /// -/// Spawns `n` worker tasks and replenishes the pool if any worker tasks +/// Spawns `n` worker threads and replenishes the pool if any worker threads /// panic. /// /// # Example @@ -69,34 +69,34 @@ impl<'a> Drop for Sentinel<'a> { /// assert_eq!(rx.iter().take(8u).sum(), 8u); /// ``` pub struct TaskPool { - // How the taskpool communicates with subtasks. + // How the threadpool communicates with subthreads. // - // This is the only such Sender, so when it is dropped all subtasks will + // This is the only such Sender, so when it is dropped all subthreads will // quit. jobs: Sender } impl TaskPool { - /// Spawns a new task pool with `tasks` tasks. + /// Spawns a new thread pool with `threads` threads. /// /// # Panics /// - /// This function will panic if `tasks` is 0. - pub fn new(tasks: uint) -> TaskPool { - assert!(tasks >= 1); + /// This function will panic if `threads` is 0. + pub fn new(threads: uint) -> TaskPool { + assert!(threads >= 1); let (tx, rx) = channel::(); let rx = Arc::new(Mutex::new(rx)); - // Taskpool tasks. - for _ in range(0, tasks) { + // Threadpool threads + for _ in range(0, threads) { spawn_in_pool(rx.clone()); } TaskPool { jobs: tx } } - /// Executes the function `job` on a task in the pool. + /// Executes the function `job` on a thread in the pool. pub fn execute(&self, job: F) where F : FnOnce(), F : Send { @@ -106,7 +106,7 @@ impl TaskPool { fn spawn_in_pool(jobs: Arc>>) { Thread::spawn(move |:| { - // Will spawn a new task on panic unless it is cancelled. + // Will spawn a new thread on panic unless it is cancelled. let sentinel = Sentinel::new(&jobs); loop { @@ -165,12 +165,12 @@ mod test { let pool = TaskPool::new(TEST_TASKS); - // Panic all the existing tasks. + // Panic all the existing threads. for _ in range(0, TEST_TASKS) { pool.execute(move|| -> () { panic!() }); } - // Ensure new tasks were spawned to compensate. + // Ensure new threads were spawned to compensate. let (tx, rx) = channel(); for _ in range(0, TEST_TASKS) { let tx = tx.clone(); @@ -189,7 +189,7 @@ mod test { let pool = TaskPool::new(TEST_TASKS); let waiter = Arc::new(Barrier::new(TEST_TASKS + 1)); - // Panic all the existing tasks in a bit. + // Panic all the existing threads in a bit. for _ in range(0, TEST_TASKS) { let waiter = waiter.clone(); pool.execute(move|| {