2014-12-28 2 views
2

У меня есть проблемы с пониманием поведения программы в 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); 
} 

В частности, я не понимаю, почему некоторые задачи не удается достичь этой линии, когда будучи оторванными:

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

Но не тогда, когда при соединении с родительским (основным).

Кроме того, почему только вложенные задачи выполняются в заранее определенном порядке?

ответ

1

Вам необходимо запустить код несколько раз, потому что порядок исполнения нитей не гарантируются. Я также не знаю, сколько параллельных процессоров допускает онлайн-оценку, поэтому вы можете запускать ее в одноядерной машине. Я побежал его несколько раз на моем многоядерном ноутбуке и получил следующий результат:

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 

Важных нитками является то, что программа завершает , когда основной поток завершает. В этом случае необходимо рассмотреть 4 потока: основной поток и 3 потока задач. Основной поток будет выполнен, как только он получит 3 сообщения и распечатает их. Неважно, что делают остальные темы!

Когда вы используете join нить из основного потока, вы сообщаете основному потоку, чтобы ждать выхода рабочего потока. Это означает, что каждый поток сможет выполнить println! до выхода программы.

1

Этот код не входит в задачи, но отделяет его. Это означает, что задачи не зависят от основного потока (тот, который отделяет его)

Тогда два варианта для каждой задачи:

  • она закончена до Println выполняется: то вы видите его в коде с помощью печати
  • он не закончил, а затем Println вы упоминались выполнен и не дожидаясь

Если вы вступите, то это означает, что «я должен ждать для решения этой задачи, чтобы продолжить». Поэтому вся задача выполняется до выполнения строки.

Там нет никакого предопределенного порядка, что делает многопоточный код трудно отлаживать :-)

+0

Как завершить задачу перед выполнением ее кода? –

+0

Поскольку «println! (« Task {} завершен », id); является частью тела кода задачи, как можно выполнить задачу «(быть) до выполнения println»? –

+0

, потому что он выполняется в другой части программы и параллельно, то есть в потоке. Для этого используется поток. Используйте join, чтобы заставить его закончить, прежде чем продолжить. – Gabriel

Смежные вопросы