andrey
andrey

Reputation: 1585

Why do some statements fail to execute when run in a thread?

I have trouble understanding the program behaviour of this code sample:

use std::comm;
use std::thread::Thread;

static NTHREADS: uint = 3;

fn main() {
    let (tx, rx): (Sender<uint>, Receiver<uint>) = comm::channel();

    for id in range(0, NTHREADS) {
        let thread_tx = tx.clone();

        Thread::spawn(move || {
            thread_tx.send(id);
            println!("thread {} finished", id);
        }).detach();
    }

    let mut ids = Vec::with_capacity(NTHREADS);
    for _ in range(0, NTHREADS) {
        ids.push(rx.recv());
    }

    println!("{}", ids);
}

Specifically, I don't understand why some tasks fail to reach this line when being detached:

println!("task {} finished", id);

But not when when joined with the parent (main).

Also, why is it that only joined tasks are executed in pre-defined order?

Upvotes: 2

Views: 96

Answers (2)

Gabriel
Gabriel

Reputation: 3584

This code does not join tasks but detaches it. This means the tasks are independent of the main thread (the one that detaches it)

Then two options for each task:

  • it is finished before the println is executed: then you see it in the code via the print
  • it is not finished and then the println you mentionned is executed without waiting for it

If you join then it means "I have to wait for this task to carry on". Therefore all the task are executed before the line is executed.

There is no predefined order, which makes multi-threaded code hard to debug :-)

Upvotes: 1

Shepmaster
Shepmaster

Reputation: 430290

You need to run the code multiple times because the order of execution of the threads is not guaranteed. I also don't know how many concurrent processors that online evaluation is allowed, so you might be running it in a single-core machine. I ran it a few times on my multi-core laptop and got the following output:

task 0 finished
task 1 finished
task 2 finished
[0, 1, 2]

task 1 finished
task 0 finished
task 2 finished
[0, 1, 2]

task 0 finished
task 1 finished
[0, 1, 2]
task 2 finished

An important consideration with threads is that the program finishes when the main thread finishes. In this case, there are 4 threads to consider: the main thread and 3 task threads. The main thread will be done once it has received 3 messages and printed them out. It doesn't matter what the rest of the threads are doing!

When you join a thread from the main thread, you are telling the main thread to wait until the worker thread has exited. This means that each thread will be able to execute the println! before the program exits.

Upvotes: 1

Related Questions