Who is the main thread in a scoped thread in Rust programming? Is it the thread outside the spawned thread inside the scope? Or is it the thread outside the `thread::scope()` function and inside the main function?

Here is the code snippet I took from Mara Bos's book with added comments:

fn main() 
{
    let num_done = &AtomicUsize::new(0);
    thread::scope(|s| {
        // Four background threads to process all 100 items, 25 each.
       for t in 0..4 {
            s.spawn(move || {
                for i in 0..25 {
                     process_item(t * 25 + i); // Assuming this takes some time.
                     num_done.fetch_add(1, Relaxed);
                  }
            });
       }
        // The main thread shows status updates, every second. Is this main 
        //thread of this program?
        loop {
               let n = num_done.load(Relaxed);
               if n == 100 { break; }
               println!("Working.. {n}/100 done");
               thread::sleep(Duration::from_secs(1));
              }
        });
   println!("Done!");
   //Is it the main thread of this program?
}

I am confused because it seems that the main() function created a thread that is supposed to be the main thread to execute this program but the book refers the main thread from the inside of the thread::scope() function. So if I move these

loop {
       let n = num_done.load(Relaxed);
       if n == 100 { break; }
       println!("Working.. {n}/100 done");
       thread::sleep(Duration::from_secs(1));
       }

code from outside of the thread::scope() function to the main() function the loop only executed once as it finds n is 100.

What am I missing?

Thanks.

Calling std::thread::scope() doesn't create any threads nor send anything to any existing thread. So, in

// A
thread::scope(|s| {
    // B
});
// C

code in any of the positions A, B, and C runs on the same thread, whatever thread that was. thread::scope() doesn't change what thread is in use. Only spawn() (scoped or not) actually runs code on a different thread.

However, when the scope ends, it must join (wait for) all threads spawned using the scope. So if you move the loop to after the }); of the scope, then this has the effect of not starting the loop until the threads have all ended. You're changing when the code runs, not on what thread the code runs.

7 Likes

Adding to what kpreid said. You decide which thread is your "main" thread, by convention it's often the parent thread, but it doesn't have to be.
For example you could spawn a thread that will do the reporting on stdout/stderr decide this is the main thread, and spawn lots of other doing the work and leave the parent thread only the responsibility of setting up its children and joining them.

1 Like

Rust does have a specific main thread.

If the main thread panics without the panic being caught, the application will exit with a non-zero exit code.

When the main thread of a Rust program terminates, the entire program shuts down, even if other threads are still running. However, this module provides convenient facilities for automatically waiting for the termination of a thread (i.e., join).

2 Likes

That is different from what I was talking about. I was considering "main" as a nominal distinction. From my point of view I can say any one of my threads is my "main" one. I could consider a reporting thread to be my most important, I could consider a worker thread to be extremely capital.

1 Like