Concurrency in Rust

Concurrency in Rust means different parts of a program running or getting executed consequently. There is also the concept of independent or parallel execution, where parts of a single process can execute independently. This is where concurrency comes into play.

The two concepts are:

  • Independent Executions : In concurrent programmings, different parts of a single program execute independently. This is done by processor scheduling algorithms.
  • Parallel Executions : In parallel programmings, different parts of the program get executed parallelly. This can be done by using multiple processors and using the concept of parallel processing.

Concept of Thread:

Simply speaking, a thread is nothing, but a small unit of execution, which can start the execution of a process. A thread will generally contain some important parameters of the process such as- Program Counter, stack, a unique ID of the process, etc.

However, a thread can not get executed by itself and must be contained inside the process itself. A process must have a single thread to get started in a computer system. There can be multiple threads inside a process.

All the threads of the same process will always contain all the attributed which are required to get access to the systems memory or any allocations of hardware units that are responsible for the program execution.

In single words, a thread can be termed as the starter of a process.

What is thread important is Concurrency?

The are various reasons for which threads are important in the Concept of Concurrency of parallel executions. The most important are:

  • A thread assigned to a part of the process can initiate the program execution. This is important when we have to execute different parts of the same program or process independently.
  • A thread contains all the necessary parameters which are required to start the execution of a process. Therefore, when parts of a process have to be executed independently, then these parameters are important to get access to the hardware as memory allocations. Here, the thread is the only key to achieve this.
  • A thread can help you, to execute different parts of the same program for getting executed in different processors. This is helpful in multi-tasking and multi-programming, where we use multiple processors.

Creating a thread in Rust

A thread in Rust can be simply created using the keyword thread::spawn. Inside the spawn function, we write some code that gets executed when the particular thread is initiated. The code inside the spawn function is itself called the parameter of the function.

Steps to use thread in Rust :

  • Import the standard thread library of Rust, by writing use::std:: thread; at the start of the program.
  • Use a delay function to indicate, that for how much time the thread should sleep or pause for the next execution. This can be done by writing use::std::time::Duration; at the start of the program.
  • Define a new thread by writing thread::spawn and use the code as a closure to the spawn() function.
  • Use a thread::sleep() function if you want to see the sequences of execution.
This can be noted that, the main() function will also create a main thread exactly when the program starts getting executed.

A program to create a thread and see how a user created thread differs from the main thread.

In the below program, we have imported std::thread and std::time::Duration from the Rust library simple by writing use std::thread; and use std::time::Duration; at the start of the program.

use std::thread;
use std::time::Duration;
fn main() {
    thread::spawn( || {
    thread::sleep(Duration::from_millis(2000));
    println!("The thread stopped after 2 seconds");
    println!("wait for 4 seconds from now till the main thread ends");
 });
  println!("The main function execution started");
  thread::sleep(Duration::from_millis(6000));
  println!("the main thread stops after 4 seconds")
}

Inside the main() function we have created a new thread by using thread::spawn(||) . Then we have declared the function called thread::sleep to indicate how much time the thread should wait to finish.

This is done using thread::sleep(Duration::from_millis(2000));. Then we used macro println!() to show that the thread ended and we must wait to see when the main thread stops.

Please read these points carefully :

  • Irrespective of the completion time of the user-created thread, the main thread will continue till the time mentioned. In our case, the main thread should wait for 6 seconds for completion.
  • But, the user-created thread has a wait time of 2 seconds. However, both the wait time starts concurrently. This is where the concurrency comes into play.
  • Now, when the user-created thread has elapsed 2 seconds, by that time the main thread has also elapsed two seconds.
  • The user-created thread stops after 2 seconds(as its completion time is two seconds.)
  • The main thread has more 4 seconds to wait. (As its total completion time is 6 seconds. 2 seconds covered along with the user-created thread, and 4 seconds the main thread will wait alone).

We shall show the program output separately, to show how the delay happens.

Program Output :

rust-concurrency-demo-one

After 2 Seconds :

rust-concurrency-demo-two

After 4 Seconds :

rust-concurrency-demo-three

Cheers ! you have successfully, created your thread and have seen the output.

The drawback of thread and its solution

The drawback of the user-created thread is that the thread can only execute till the main thread completed. It means, that if we induce a delay in our user-created thread, to end it after 5 seconds, and the main thread is induced with a delay of 2 seconds.

In such cases, the user-created thread will be stopped after 2 seconds, since the main thread can reach up to 2 seconds.

In this type of scenario, the spawned thread(user-created) is fully dependent on the main thread completion time and may have to stop without completion.

Let us consider an example to understand this. (A program where the thread does not get executed)

use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn( || {
        thread::sleep(Duration::from_millis(10000));
        println!("Sorry chercher.tech, i will not be printed");
 });
    println!("The main function execution started");
    thread::sleep(Duration::from_millis(2000));
    println!("the main thread stops after 2 seconds");
    println!("Sorry! The spawned thread could not be executed");
    println!("As it crosses the time limit of main thread");
}

In the above program, we can see that our spawned thread has a delay of 10000 milli-seconds(10 Seconds). And our main thread has a duration of 2000 milli-seconds(2 Seconds).

The macro println!() with text Sorry chercher.tech, i will not be printed, inside the spawned thread will never get executed as the main thread will complete after 2 seconds, and it will not allow the spawned thread to complete its execution, as it would take (10-2= 8 Seconds) more to get executed.

It means the completion of the main thread will interrupt the spawned thread.

Program Output :

rust-concurrency-thread-early-interruption

Solution to this problem

The solution is very simple, just we have to tell the compiler that the main thread should wait till the spawned thread completes. This can be done simply by naming the spawned thread and then mentioning the thread name along with with the join() function, as the last statement of the main() function.

A program to let a thread execute:

use std::thread;
use std::time::Duration;

fn main() {
    let mythread = thread::spawn( || {
        thread::sleep(Duration::from_millis(10000));
        println!("Now i am independent of the main thread time");
    });
    println!("The main function execution started");
    thread::sleep(Duration::from_millis(2000));
    println!("the main thread stops after 2 seconds");
    println!("Wait.. The spawned thread will execute");
    mythread.join();
}

In the above program, we have named the thread as mythread. And simply, as the last statement, we have added the line- mythread.join().unwrap(); . This line will join the main thread and the spawned thread.

Program Output :

rust-concurrency-thread-join

Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions