rollup merge of #20615: aturon/stab-2-thread

This commit takes a first pass at stabilizing `std::thread`:

* It removes the `detach` method in favor of two constructors -- `spawn`
  for detached threads, `scoped` for "scoped" (i.e., must-join)
  threads. This addresses some of the surprise/frustrating debug
  sessions with the previous API, in which `spawn` produced a guard that
  on destruction joined the thread (unless `detach` was called).

  The reason to have the division in part is that `Send` will soon not
  imply `'static`, which means that `scoped` thread creation can take a
  closure over *shared stack data* of the parent thread. On the other
  hand, this means that the parent must not pop the relevant stack
  frames while the child thread is running. The `JoinGuard` is used to
  prevent this from happening by joining on drop (if you have not
  already explicitly `join`ed.) The APIs around `scoped` are
  future-proofed for the `Send` changes by taking an additional lifetime
  parameter. With the current definition of `Send`, this is forced to be
  `'static`, but when `Send` changes these APIs will gain their full
  flexibility immediately.

  Threads that are `spawn`ed, on the other hand, are detached from the
  start and do not yield an RAII guard.

  The hope is that, by making `scoped` an explicit opt-in with a very
  suggestive name, it will be drastically less likely to be caught by a
  surprising deadlock due to an implicit join at the end of a scope.

* The module itself is marked stable.

* Existing methods other than `spawn` and `scoped` are marked stable.

The migration path is:

```rust
Thread::spawn(f).detached()
```

becomes

```rust
Thread::spawn(f)
```

while

```rust
let res = Thread::spawn(f);
res.join()
```

becomes

```rust
let res = Thread::scoped(f);
res.join()
```

[breaking-change]
This commit is contained in:
Alex Crichton 2015-01-06 15:38:38 -08:00
commit 36f5d122b8
97 changed files with 361 additions and 293 deletions

View file

@ -15,6 +15,6 @@ pub fn foo<T:Send + Clone>(x: T) -> Receiver<T> {
let (tx, rx) = channel();
Thread::spawn(move|| {
tx.send(x.clone());
}).detach();
});
rx
}

View file

@ -64,7 +64,7 @@ fn run(args: &[String]) {
let mut worker_results = Vec::new();
for _ in range(0u, workers) {
let to_child = to_child.clone();
worker_results.push(Thread::spawn(move|| {
worker_results.push(Thread::scoped(move|| {
for _ in range(0u, size / workers) {
//println!("worker {}: sending {} bytes", i, num_bytes);
to_child.send(request::bytes(num_bytes)).unwrap();
@ -74,7 +74,7 @@ fn run(args: &[String]) {
}
Thread::spawn(move|| {
server(&from_parent, &to_parent);
}).detach();
});
for r in worker_results.into_iter() {
let _ = r.join();

View file

@ -59,7 +59,7 @@ fn run(args: &[String]) {
let mut worker_results = Vec::new();
let from_parent = if workers == 1 {
let (to_child, from_parent) = channel();
worker_results.push(Thread::spawn(move|| {
worker_results.push(Thread::scoped(move|| {
for _ in range(0u, size / workers) {
//println!("worker {}: sending {} bytes", i, num_bytes);
to_child.send(request::bytes(num_bytes));
@ -71,7 +71,7 @@ fn run(args: &[String]) {
let (to_child, from_parent) = channel();
for _ in range(0u, workers) {
let to_child = to_child.clone();
worker_results.push(Thread::spawn(move|| {
worker_results.push(Thread::scoped(move|| {
for _ in range(0u, size / workers) {
//println!("worker {}: sending {} bytes", i, num_bytes);
to_child.send(request::bytes(num_bytes));
@ -83,7 +83,7 @@ fn run(args: &[String]) {
};
Thread::spawn(move|| {
server(&from_parent, &to_parent);
}).detach();
});
for r in worker_results.into_iter() {
let _ = r.join();

View file

@ -35,7 +35,7 @@ fn ping_pong_bench(n: uint, m: uint) {
// Create a channel: B->A
let (btx, brx) = channel();
let guard_a = Thread::spawn(move|| {
let guard_a = Thread::scoped(move|| {
let (tx, rx) = (atx, brx);
for _ in range(0, n) {
tx.send(()).unwrap();
@ -43,7 +43,7 @@ fn ping_pong_bench(n: uint, m: uint) {
}
});
let guard_b = Thread::spawn(move|| {
let guard_b = Thread::scoped(move|| {
let (tx, rx) = (btx, arx);
for _ in range(0, n) {
rx.recv().unwrap();

View file

@ -25,7 +25,7 @@ fn parfib(n: uint) -> uint {
let (tx, rx) = channel();
Thread::spawn(move|| {
tx.send(parfib(n-1));
}).detach();
});
let m2 = parfib(n-2);
return (rx.recv().unwrap() + m2);
}

View file

@ -95,7 +95,7 @@ fn main() {
let mut messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
use std::num::Int;
let iterations = 2i.pow((max_depth - depth + min_depth) as uint);
Thread::spawn(move|| {
Thread::scoped(move|| {
let mut chk = 0;
for i in range(1, iterations + 1) {
let arena = TypedArena::new();

View file

@ -195,7 +195,7 @@ fn rendezvous(nn: uint, set: Vec<Color>) {
from_rendezvous,
to_rendezvous,
to_rendezvous_log);
}).detach();
});
to_creature
}).collect();

View file

@ -168,7 +168,7 @@ fn fannkuch(n: i32) -> (i32, i32) {
for (i, j) in range(0, N).zip(iter::count(0, k)) {
let max = cmp::min(j+k, perm.max());
futures.push(Thread::spawn(move|| {
futures.push(Thread::scoped(move|| {
work(perm, j as uint, max as uint)
}))
}

View file

@ -173,7 +173,7 @@ fn main() {
Thread::spawn(move|| {
make_sequence_processor(sz, &from_parent, &to_parent_);
}).detach();
});
to_child
}).collect::<Vec<Sender<Vec<u8> >> >();

View file

@ -304,11 +304,11 @@ fn main() {
let nb_freqs: Vec<_> = range(1u, 3).map(|i| {
let input = input.clone();
(i, Thread::spawn(move|| generate_frequencies(input.as_slice(), i)))
(i, Thread::scoped(move|| generate_frequencies(input.as_slice(), i)))
}).collect();
let occ_freqs: Vec<_> = OCCURRENCES.iter().map(|&occ| {
let input = input.clone();
Thread::spawn(move|| generate_frequencies(input.as_slice(), occ.len()))
Thread::scoped(move|| generate_frequencies(input.as_slice(), occ.len()))
}).collect();
for (i, freq) in nb_freqs.into_iter() {

View file

@ -82,7 +82,7 @@ fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
let mut precalc_i = Vec::with_capacity(h);
let precalc_futures = range(0, WORKERS).map(|i| {
Thread::spawn(move|| {
Thread::scoped(move|| {
let mut rs = Vec::with_capacity(w / WORKERS);
let mut is = Vec::with_capacity(w / WORKERS);
@ -123,7 +123,7 @@ fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
let vec_init_r = arc_init_r.clone();
let vec_init_i = arc_init_i.clone();
Thread::spawn(move|| {
Thread::scoped(move|| {
let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
let init_r_slice = vec_init_r.as_slice();

View file

@ -321,7 +321,7 @@ fn par_search(masks: Vec<Vec<Vec<u64>>>) -> Data {
let mut data = Data::new();
search(&*masks, m, 1, List::Cons(m, &List::Nil), &mut data);
tx.send(data).unwrap();
}).detach();
});
}
// collecting the results

View file

@ -35,15 +35,15 @@ fn fib(n: int) -> int {
} else {
let (tx1, rx) = channel();
let tx2 = tx1.clone();
Thread::spawn(move|| pfib(&tx2, n - 1)).detach();
Thread::spawn(move|| pfib(&tx2, n - 1));
let tx2 = tx1.clone();
Thread::spawn(move|| pfib(&tx2, n - 2)).detach();
Thread::spawn(move|| pfib(&tx2, n - 2));
tx.send(rx.recv().unwrap() + rx.recv().unwrap());
}
}
let (tx, rx) = channel();
Thread::spawn(move|| pfib(&tx, n) ).detach();
Thread::spawn(move|| pfib(&tx, n) );
rx.recv().unwrap()
}
@ -78,7 +78,7 @@ fn stress_task(id: int) {
fn stress(num_tasks: int) {
let mut results = Vec::new();
for i in range(0, num_tasks) {
results.push(Thread::spawn(move|| {
results.push(Thread::scoped(move|| {
stress_task(i);
}));
}

View file

@ -46,10 +46,10 @@ fn start(n_tasks: int, token: int) {
tx.send(token);
for i in range(2, n_tasks + 1) {
let (tx, next_rx) = channel();
Thread::spawn(move|| roundtrip(i, tx, rx)).detach();
Thread::spawn(move|| roundtrip(i, tx, rx));
rx = next_rx;
}
Thread::spawn(move|| roundtrip(1, tx, rx)).detach();
Thread::spawn(move|| roundtrip(1, tx, rx));
}
fn roundtrip(id: int, tx: Sender<int>, rx: Receiver<int>) {

View file

@ -36,7 +36,7 @@ fn main() {
fn run(repeat: int, depth: int) {
for _ in range(0, repeat) {
let dur = Duration::span(|| {
let _ = Thread::spawn(move|| {
let _ = Thread::scoped(move|| {
recurse_or_panic(depth, None)
}).join();
});

View file

@ -35,7 +35,7 @@ fn child_generation(gens_left: uint, tx: Sender<()>) {
} else {
tx.send(()).unwrap()
}
}).detach();
});
}
fn main() {

View file

@ -15,7 +15,7 @@ use std::thread::Thread;
fn f(n: uint) {
let mut i = 0u;
while i < n {
let _ = Thread::spawn(move|| g()).join();
let _ = Thread::scoped(move|| g()).join();
i += 1u;
}
}
@ -33,5 +33,5 @@ fn main() {
};
let n = args[1].parse().unwrap();
let mut i = 0u;
while i < n { Thread::spawn(move|| f(n) ).detach(); i += 1u; }
while i < n { Thread::spawn(move|| f(n) ); i += 1u; }
}

View file

@ -13,7 +13,7 @@
use std::thread::Thread;
fn main() {
let r: Result<int,_> = Thread::spawn(move|| {
let r: Result<int,_> = Thread::scoped(move|| {
panic!("test");
1i
}).join();

View file

@ -13,7 +13,7 @@
use std::thread::Builder;
fn main() {
let r: Result<int,_> = Builder::new().name("owned name".to_string()).spawn(move|| {
let r: Result<int,_> = Builder::new().name("owned name".to_string()).scoped(move|| {
panic!("test");
1i
}).join();

View file

@ -15,7 +15,7 @@ use std::thread::Thread;
fn main() {
// the purpose of this test is to make sure that task::spawn()
// works when provided with a bare function:
let r = Thread::spawn(startfn).join();
let r = Thread::scoped(startfn).join();
if r.is_err() {
panic!()
}

View file

@ -22,7 +22,7 @@ impl Drop for A {
}
fn main() {
Thread::spawn(move|| {
Thread::scoped(move|| {
let _a = A;
lib::callback(|| panic!());
1i

View file

@ -45,5 +45,5 @@ pub fn fails() {
}
pub fn main() {
Thread::spawn(fails).join();
Thread::scoped(fails).join();
}

View file

@ -90,7 +90,7 @@ pub fn test_destroy_actually_kills(force: bool) {
_ = rx2.recv() => unsafe { libc::exit(1) },
_ = rx1.recv() => {}
}
}).detach();
});
match p.wait().unwrap() {
ExitStatus(..) => panic!("expected a signal"),
ExitSignal(..) => tx.send(()).unwrap(),

View file

@ -21,7 +21,7 @@ extern {
pub fn main() {
unsafe {
Thread::spawn(move|| {
Thread::scoped(move|| {
let i = &100i;
rust_dbg_call(callback, mem::transmute(i));
}).join();

View file

@ -1,4 +1,3 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
@ -37,7 +36,7 @@ mod map_reduce {
for i in inputs.iter() {
let ctrl = ctrl.clone();
let i = i.clone();
Thread::spawn(move|| map_task(ctrl.clone(), i.clone()) ).detach();
Thread::spawn(move|| map_task(ctrl.clone(), i.clone()) );
}
}

View file

@ -12,7 +12,7 @@ use std::time::Duration;
use std::thread::Thread;
fn main() {
Thread::spawn(move|| customtask()).join().ok().unwrap();
Thread::scoped(move|| customtask()).join().ok().unwrap();
}
fn customtask() {

View file

@ -22,7 +22,7 @@ fn helper(rx: Receiver<Sender<()>>) {
fn main() {
let (tx, rx) = channel();
let _t = Thread::spawn(move|| { helper(rx) }).detach();
let _t = Thread::spawn(move|| { helper(rx) });
let (snd, rcv) = channel::<int>();
for _ in range(1i, 100000i) {
snd.send(1i).unwrap();

View file

@ -20,7 +20,7 @@ fn main() {
// Check that both closures are capturing by value
assert_eq!(1, mem::size_of_val(&closure));
Thread::spawn(move|| {
Thread::scoped(move|| {
let ok = closure;
}).join().ok().unwrap();
}

View file

@ -24,5 +24,5 @@ pub fn main() {
let mut stdin = std::io::stdin();
Thread::spawn(move|| {
let _ = stdin.read_to_end();
}).detach();
});
}

View file

@ -14,7 +14,7 @@ use std::thunk::Thunk;
static generations: uint = 1024+256+128+49;
fn spawn(f: Thunk) {
Builder::new().stack_size(32 * 1024).spawn(move|| f.invoke(())).detach()
Builder::new().stack_size(32 * 1024).spawn(move|| f.invoke(()));
}
fn child_no(x: uint) -> Thunk {

View file

@ -17,7 +17,7 @@ pub fn main() {
tx.send("hello, world").unwrap();
Thread::spawn(move|| {
Thread::scoped(move|| {
println(rx.recv().unwrap());
}).join().ok().unwrap();
}

View file

@ -14,7 +14,7 @@ use std::thread::Thread;
pub fn main() {
let (tx, rx) = channel::<&'static str>();
let t = Thread::spawn(move|| {
let t = Thread::scoped(move|| {
assert_eq!(rx.recv().unwrap(), "hello, world");
});

View file

@ -12,24 +12,24 @@ use std::{int, i8, i16, i32, i64};
use std::thread::Thread;
fn main() {
assert!(Thread::spawn(move|| int::MIN / -1).join().is_err());
assert!(Thread::spawn(move|| i8::MIN / -1).join().is_err());
assert!(Thread::spawn(move|| i16::MIN / -1).join().is_err());
assert!(Thread::spawn(move|| i32::MIN / -1).join().is_err());
assert!(Thread::spawn(move|| i64::MIN / -1).join().is_err());
assert!(Thread::spawn(move|| 1i / 0).join().is_err());
assert!(Thread::spawn(move|| 1i8 / 0).join().is_err());
assert!(Thread::spawn(move|| 1i16 / 0).join().is_err());
assert!(Thread::spawn(move|| 1i32 / 0).join().is_err());
assert!(Thread::spawn(move|| 1i64 / 0).join().is_err());
assert!(Thread::spawn(move|| int::MIN % -1).join().is_err());
assert!(Thread::spawn(move|| i8::MIN % -1).join().is_err());
assert!(Thread::spawn(move|| i16::MIN % -1).join().is_err());
assert!(Thread::spawn(move|| i32::MIN % -1).join().is_err());
assert!(Thread::spawn(move|| i64::MIN % -1).join().is_err());
assert!(Thread::spawn(move|| 1i % 0).join().is_err());
assert!(Thread::spawn(move|| 1i8 % 0).join().is_err());
assert!(Thread::spawn(move|| 1i16 % 0).join().is_err());
assert!(Thread::spawn(move|| 1i32 % 0).join().is_err());
assert!(Thread::spawn(move|| 1i64 % 0).join().is_err());
assert!(Thread::scoped(move|| int::MIN / -1).join().is_err());
assert!(Thread::scoped(move|| i8::MIN / -1).join().is_err());
assert!(Thread::scoped(move|| i16::MIN / -1).join().is_err());
assert!(Thread::scoped(move|| i32::MIN / -1).join().is_err());
assert!(Thread::scoped(move|| i64::MIN / -1).join().is_err());
assert!(Thread::scoped(move|| 1i / 0).join().is_err());
assert!(Thread::scoped(move|| 1i8 / 0).join().is_err());
assert!(Thread::scoped(move|| 1i16 / 0).join().is_err());
assert!(Thread::scoped(move|| 1i32 / 0).join().is_err());
assert!(Thread::scoped(move|| 1i64 / 0).join().is_err());
assert!(Thread::scoped(move|| int::MIN % -1).join().is_err());
assert!(Thread::scoped(move|| i8::MIN % -1).join().is_err());
assert!(Thread::scoped(move|| i16::MIN % -1).join().is_err());
assert!(Thread::scoped(move|| i32::MIN % -1).join().is_err());
assert!(Thread::scoped(move|| i64::MIN % -1).join().is_err());
assert!(Thread::scoped(move|| 1i % 0).join().is_err());
assert!(Thread::scoped(move|| 1i8 % 0).join().is_err());
assert!(Thread::scoped(move|| 1i16 % 0).join().is_err());
assert!(Thread::scoped(move|| 1i32 % 0).join().is_err());
assert!(Thread::scoped(move|| 1i64 % 0).join().is_err());
}

View file

@ -26,7 +26,7 @@ fn periodical(n: int) -> Receiver<bool> {
Err(..) => break
}
}
}).detach();
});
return port;
}
@ -41,7 +41,7 @@ fn integers() -> Receiver<int> {
}
i = i + 1;
}
}).detach();
});
return port;
}
@ -58,4 +58,3 @@ fn main() {
}
}
}

View file

@ -27,7 +27,7 @@ impl fmt::Show for Foo {
}
pub fn main() {
Thread::spawn(move|| {
Thread::scoped(move|| {
let mut f = Foo(Cell::new(0));
println!("{:?}", f);
let Foo(ref mut f) = f;

View file

@ -14,7 +14,7 @@ macro_rules! expr { ($e: expr) => { $e } }
macro_rules! spawn {
($($code: tt)*) => {
expr!(Thread::spawn(move|| {$($code)*}).detach())
expr!(Thread::spawn(move|| {$($code)*}))
}
}

View file

@ -23,7 +23,7 @@ impl Drop for A {
}
fn main() {
Thread::spawn(move|| -> () {
Thread::scoped(move|| -> () {
let _a = A;
panic!();
}).join().unwrap_err();

View file

@ -33,10 +33,9 @@ impl Drop for B {
}
pub fn main() {
let ret = Thread::spawn(move|| {
let ret = Thread::scoped(move|| {
let _a = A { b: B { foo: 3 } };
}).join();
assert!(ret.is_err());
unsafe { assert!(dropped); }
}

View file

@ -22,7 +22,7 @@ fn test05() {
println!("{}", *three + n); // will copy x into the closure
assert_eq!(*three, 3);
};
Thread::spawn(move|| {
Thread::scoped(move|| {
test05_start(fn_to_send);
}).join().ok().unwrap();
}

View file

@ -36,5 +36,5 @@ mod b {
}
fn main() {
Thread::spawn(move|| { ::b::g() }).join().unwrap_err();
Thread::scoped(move|| { ::b::g() }).join().unwrap_err();
}

View file

@ -28,6 +28,6 @@ fn foo() {
}
fn main() {
let _ = Thread::spawn(move|| foo()).join();
let _ = Thread::scoped(move|| foo()).join();
unsafe { assert!(DTOR_COUNT == 2); }
}

View file

@ -32,6 +32,6 @@ fn foo() {
}
fn main() {
let _ = Thread::spawn(move|| foo()).join();
let _ = Thread::scoped(move|| foo()).join();
unsafe { assert!(DTOR_COUNT == 2); }
}

View file

@ -25,6 +25,6 @@ fn iotask(_tx: &ctx, ip: String) {
pub fn main() {
let (tx, _rx) = channel::<int>();
let t = Thread::spawn(move|| iotask(&tx, "localhost".to_string()) );
let t = Thread::scoped(move|| iotask(&tx, "localhost".to_string()) );
t.join().ok().unwrap();
}

View file

@ -11,7 +11,7 @@
use std::thread::Thread;
pub fn main() {
Thread::spawn(move|| child(10)).join().ok().unwrap();
Thread::scoped(move|| child(10)).join().ok().unwrap();
}
fn child(i: int) { println!("{}", i); assert!((i == 10)); }

View file

@ -11,7 +11,7 @@
use std::thread::Thread;
pub fn main() {
let t = Thread::spawn(move|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) );
let t = Thread::scoped(move|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) );
t.join().ok().unwrap();
}

View file

@ -17,5 +17,5 @@ use std::thread::Builder;
pub fn main() {
let mut t = Builder::new();
t.spawn(move|| ()).detach();
t.spawn(move|| ());
}

View file

@ -15,6 +15,6 @@ pub fn main() { test00(); }
fn start() { println!("Started / Finished task."); }
fn test00() {
let _ = Thread::spawn(move|| start() ).join();
let _ = Thread::scoped(move|| start() ).join();
println!("Completing.");
}

View file

@ -16,7 +16,7 @@ fn start(_task_number: int) { println!("Started / Finished task."); }
fn test00() {
let i: int = 0;
let mut result = Thread::spawn(move|| {
let mut result = Thread::scoped(move|| {
start(i)
});

View file

@ -19,6 +19,6 @@ fn start(tx: &Sender<int>, start: int, number_of_messages: int) {
pub fn main() {
println!("Check that we don't deadlock.");
let (tx, rx) = channel();
let _ = Thread::spawn(move|| { start(&tx, 0, 10) }).join();
let _ = Thread::scoped(move|| { start(&tx, 0, 10) }).join();
println!("Joined task");
}

View file

@ -19,7 +19,7 @@ pub fn main() {
while (i > 0) {
println!("{}", i);
let tx = tx.clone();
Thread::spawn({let i = i; move|| { child(i, &tx) }}).detach();
Thread::spawn({let i = i; move|| { child(i, &tx) }});
i = i - 1;
}

View file

@ -18,5 +18,5 @@ fn f() {
}
pub fn main() {
let _t = Thread::spawn(move|| f() ).join();
let _t = Thread::scoped(move|| f() ).join();
}

View file

@ -40,7 +40,7 @@ fn test00() {
let mut results = Vec::new();
while i < number_of_tasks {
let tx = tx.clone();
results.push(Thread::spawn({
results.push(Thread::scoped({
let i = i;
move|| {
test00_start(&tx, i, number_of_messages)

View file

@ -24,7 +24,7 @@ fn test00() {
let (tx, rx) = channel();
let number_of_messages: int = 10;
let result = Thread::spawn(move|| {
let result = Thread::scoped(move|| {
test00_start(&tx, number_of_messages);
});

View file

@ -17,7 +17,7 @@ fn main() {
let mut reader = ChanReader::new(rx);
let stderr = ChanWriter::new(tx);
let res = thread::Builder::new().stderr(box stderr as Box<Writer + Send>).spawn(move|| -> () {
let res = thread::Builder::new().stderr(box stderr as Box<Writer + Send>).scoped(move|| -> () {
panic!("Hello, world!")
}).join();
assert!(res.is_err());

View file

@ -52,7 +52,7 @@ fn test() {
}
}
srv_tx.send(());
}).detach();
});
}
for _ in range(0, N) {
@ -62,7 +62,7 @@ fn test() {
let _s = TcpStream::connect(addr).unwrap();
}
cli_tx.send(());
}).detach();
});
}
drop((cli_tx, srv_tx));

View file

@ -29,7 +29,7 @@ fn main() {
timer::sleep(Duration::milliseconds(30 * 1000));
println!("timed out!");
unsafe { libc::exit(1) }
}).detach();
});
let (tx, rx) = channel();
Thread::spawn(move || -> () {
@ -47,7 +47,7 @@ fn main() {
stream.read_byte();
stream.write(&[2]);
}
}).detach();
});
let addr = rx.recv().unwrap();
let (tx, rx) = channel();
@ -64,7 +64,7 @@ fn main() {
Err(e) => debug!("{}", e)
}
tx.send(()).unwrap();
}).detach();
});
}
// Wait for all clients to exit, but don't wait for the server to exit. The

View file

@ -42,7 +42,7 @@ fn test_rm_tempdir() {
tx.send(tmp.path().clone()).unwrap();
panic!("panic to unwind past `tmp`");
};
let _ = Thread::spawn(f).join();
let _ = Thread::scoped(f).join();
let path = rx.recv().unwrap();
assert!(!path.exists());
@ -52,7 +52,7 @@ fn test_rm_tempdir() {
let _tmp = tmp;
panic!("panic to unwind past `tmp`");
};
let _ = Thread::spawn(f).join();
let _ = Thread::scoped(f).join();
assert!(!path.exists());
let path;
@ -60,7 +60,7 @@ fn test_rm_tempdir() {
let f = move|:| {
TempDir::new("test_rm_tempdir").unwrap()
};
let tmp = Thread::spawn(f).join().ok().expect("test_rm_tmdir");
let tmp = Thread::scoped(f).join().ok().expect("test_rm_tmdir");
path = tmp.path().clone();
assert!(path.exists());
}
@ -84,7 +84,7 @@ fn test_rm_tempdir_close() {
tmp.close();
panic!("panic when unwinding past `tmp`");
};
let _ = Thread::spawn(f).join();
let _ = Thread::scoped(f).join();
let path = rx.recv().unwrap();
assert!(!path.exists());
@ -95,7 +95,7 @@ fn test_rm_tempdir_close() {
tmp.close();
panic!("panic when unwinding past `tmp`");
};
let _ = Thread::spawn(f).join();
let _ = Thread::scoped(f).join();
assert!(!path.exists());
let path;
@ -103,7 +103,7 @@ fn test_rm_tempdir_close() {
let f = move|:| {
TempDir::new("test_rm_tempdir").unwrap()
};
let tmp = Thread::spawn(f).join().ok().expect("test_rm_tmdir");
let tmp = Thread::scoped(f).join().ok().expect("test_rm_tmdir");
path = tmp.path().clone();
assert!(path.exists());
tmp.close();
@ -177,7 +177,7 @@ pub fn test_rmdir_recursive_ok() {
}
pub fn dont_double_panic() {
let r: Result<(), _> = Thread::spawn(move|| {
let r: Result<(), _> = Thread::scoped(move|| {
let tmpdir = TempDir::new("test").unwrap();
// Remove the temporary directory so that TempDir sees
// an error on drop

View file

@ -22,13 +22,13 @@ fn test_ret() { let _x: Box<int> = return; }
fn test_panic() {
fn f() { let _x: Box<int> = panic!(); }
Thread::spawn(move|| f() ).join().err().unwrap();
Thread::scoped(move|| f() ).join().err().unwrap();
}
fn test_panic_indirect() {
fn f() -> ! { panic!(); }
fn g() { let _x: Box<int> = f(); }
Thread::spawn(move|| g() ).join().err().unwrap();
Thread::scoped(move|| g() ).join().err().unwrap();
}
pub fn main() {

View file

@ -13,7 +13,7 @@ use std::thread::Thread;
pub fn main() {
let mut i = 10;
while i > 0 {
Thread::spawn({let i = i; move|| child(i)}).detach();
Thread::spawn({let i = i; move|| child(i)});
i = i - 1;
}
println!("main thread exiting");

View file

@ -23,7 +23,7 @@ pub fn main() {
let tx = tx.clone();
Thread::spawn(move|| {
child(&tx, i)
}).detach();
});
expected += i;
}

View file

@ -22,7 +22,7 @@ impl Drop for Foo {
}
pub fn main() {
let x = Thread::spawn(move|| {
let x = Thread::scoped(move|| {
let _b = Foo;
}).join();

View file

@ -77,7 +77,7 @@ pub fn main() {
let v = main.clone();
let _ = Thread::spawn(move|| {
let _ = Thread::scoped(move|| {
let mut v = v;
let mut panic_countdown = panic_countdown;
v.as_mut_slice().sort_by(|a, b| {

View file

@ -11,7 +11,7 @@
use std::thread::Thread;
pub fn main() {
let mut result = Thread::spawn(child);
let mut result = Thread::scoped(child);
println!("1");
Thread::yield_now();
println!("2");

View file

@ -11,7 +11,7 @@
use std::thread::Thread;
pub fn main() {
let mut result = Thread::spawn(child);
let mut result = Thread::scoped(child);
println!("1");
Thread::yield_now();
result.join();