Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

In contrast to the technique of messaging in which we pass ownership of objects, the shared memory technique involves borrowing objects. With those two techniques we are thus back to the traditional Rust choice between ownership and borrowing.

In this chapter, we focus on sharing memory between threads. Thanks to the Mutex structure, we will see how to share and access individual objects between threads.

38.4.1Sync

An object can be shared between threads, if its type implements the Sync trait.

38.4.2Mutexes

A mutex (mutual exclusion) is a mechanism to control access to shared data. It uses an internal lock structure to keep track of which thread is currently using the data. To access the shared data controlled by the mutex, a thread must:

  1. Acquire the lock.

  2. Read/write into the shared data.

  3. Release the lock so that other threads may access the data.

The Mutex structure implements the concept of the mutex. Some of its methods are presented in Table 1.

Table 1:Some methods of Mutex

Method

Description

clear_poison()

get_mut()

into_inner()

is_poisoned()

lock()

new(v)

Creates a new mutex on the value v.

try_lock()

38.4.3Locking

The Mutex structure provides a lock() method to acquire it. It returns a LockResult that is just an alias for the Result enumerate with a special error type PoisonError. The LockResult gives access to a MutexGuard around the data. The lock is automatically released when the MutexGuard goes out of scope.

As an example we create a mutex on an integer value:

Couldn't automatically determine type of variable `m`.
Please give it an explicit type.

We call now the lock() method to acquire the lock on the mutex. Since the lock() method returns a MutexGuard that implements RAII (Resource acquisition is initialization), it ensures that the lock will be released when getting out of scope. Hence we create a special scope, using curly braces, to force the release of the lock. The MutexGuard also implements Deref, which allows to access the underlying data through the dereferencing operator * or by calling its methods.

After the release of the lock, we can check the mutex state and see that the value has changed:

38.4.4Shared access

To share access to data between threads, we need to share a Mutex between threads. Using an Rc pointer would not work, because it is not thread-safe (i.e.: it does not handle concurrency access to its interface). Instead we are going to use an Arc pointer. Arc stands for Atomically Referenced Counted, and is just a thread-safe version of Rc.

Here is an example extracted from The Rust Programming Language book (Shared Access to Mutex<T>), in which we launch 10 threads that each increment a shared counter by 1.

We start by importing the necessary objects:

We create the counter inside a Mutex that will control its access, and we place the mutex inside an Arc so we can share it across threads:

We initialize an empty vector that will store the thread handles:

We create 10 threads. For each thread:

  1. We clone the Arc object so we can move the clone into the new thread.

  2. We spawn the new thread that will lock the mutex inside the Arc object and increment the counter. The lock is released when exiting the thread’s closure.

  3. We store the handle inside our vector.

We wait for each thread to terminate:

At the end, we check that the counter has been incremented:

see solution