CodeBlanks Logo Icon CodeBlanks

Mutex<T>

Do mutual exclusion with Mutex<T>.

Mutex<T>

Mutex<T> (mutual exclusion) lets only one thread access the data at a time. lock() returns a guard; the lock is held while the guard lives and released automatically when the guard is dropped:

use std::sync::{Arc, Mutex};

let sayac = Arc::new(Mutex::new(0));
let mut h = Vec::new();
for _ in 0..8 {
    let s = Arc::clone(&sayac);
    h.push(thread::spawn(move || {
        for _ in 0..100 {
            *s.lock().unwrap() += 1;
        }
    }));
}

In Rust the data lives inside the mutex; there's no way to reach the data without taking the lock. This makes the "forgot to lock" bug impossible.

Lock duration and deadlock

Holding the guard long makes other threads wait. If two locks are taken in different orders, two threads can wait for each other forever (deadlock). Rules: keep the lock short, don't do slow work under the lock, always take multiple locks in the same order:

{
    let mut veri = kilitli.lock().unwrap();
    veri.push(1);
}                      // the guard is dropped here, the lock opens
yavas_islem();         // without holding the lock

Rust prevents data races, but a deadlock is a logic bug and the compiler doesn't catch it.

Practice Shared counter

Share an Arc<Mutex<i32>> counter with 8 threads; let each thread increment it 100 times. After joining all threads, print the final value.

Starter code

main.rs
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // buraya yaz
}

Sample solution

main.rs
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let sayac = Arc::new(Mutex::new(0));
    let mut h = Vec::new();
    for _ in 0..8 {
        let s = Arc::clone(&sayac);
        h.push(thread::spawn(move || {
            for _ in 0..100 {
                *s.lock().unwrap() += 1;
            }
        }));
    }
    for t in h {
        t.join().unwrap();
    }
    println!("{}", *sayac.lock().unwrap());
}

Expected output

800

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Why does <code>lock()</code> return a <code>Result</code>?

  • For timeouts
  • Convention
  • If a thread holding the lock panicked, the mutex becomes "poisoned" Correct answer
  • The lock might not be obtainable

Explanation: Poisoning is a warning that the data may be inconsistent due to an interrupted update.

2 Take the lock

Question
*s.____().unwrap() += 1;
Answer
*s.lock().unwrap() += 1;

Explanation: Mutex::lock returns a guard; the data is changed through the guard.

3 Concept and meaning

Term Meaning
Mutex::lock() MutexGuard
guard drop Lock released
poisoned The holder panicked
deadlock Mutual waiting

All lessons in Advanced