Part 1. Hello threads! (10 points)

In this part, you’re going to write a very short program that will spawn several threads.

There are multiple ways to spawn threads in Rust. We’re going to use the thread::scope() method. Click the link to read its documentation, specifically the example. Pay particular attention to how the scope() function takes a closure as an argument. That closure has an argument s which is used to spawn new threads by calling s.spawn(). The spawn() method takes a (zero-argument) closure as an argument. Remember that the scope guarantees all threads will be joined at the end of the scope.

Your task

Modify the starter code in the hello directory to spawn n threads in a loop where n is the value returned by thread::available_parallelism(). This loop should be contained in the scope() function.

Note

available_parallelism returns an estimate of the default amount of parallelism a program should use. In other words, it tells you the number of computations a program can do simultaneously. If you try to use more threads than what is available, your program may actually see a degradation of performance; threads will not be able to run simultaneously, and will instead get queued until they’re able to run. You will measure performance as it relates to the number of threads used in Part 3.

The value returned by thread::available_parallelism()? is a NonZeroUsize and not a normal usize. To turn it into one, you can write your loop like

for thread_num in 0..n.into() { }

Each of your threads should print hello from its thread number. Here’s an example run of the program. Your output will likely look different since you may have a different number of threads and they will run in some unpredictable order.

$ cargo run --quiet
This program should probably only use 10 threads
Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 5
Hello from thread 6
Hello from thread 3
Hello from thread 4
Hello from thread 8
Hello from thread 9
Hello from thread 7

Make note of the number of threads your program uses; this will be useful in Part 3.