ProgramGuru

Channels, Arc and Mutex

Channels, Arc and Mutex

Workers can communicate by sending messages or by coordinating access to shared data. A channel transfers values between participants. Arc keeps shared ownership across threads, and Mutex controls exclusive access to its protected value. These tools have different responsibilities.

What you’ll learn

  • Choose messages or synchronized shared data for communication.
  • Explain the separate roles of Arc, Mutex and join.

Channels, Arc and Mutex in action

  1. Channel transfers mark 80

    Recv obtains 80 before main prints the first line.

    Channel transfers mark 80
  2. Mutex protects two increments

    Each counter worker acquires exclusive access and increments once.

    Mutex protects two increments
  3. Join all: final count 2

    Joining both workers establishes their completion; the final lock then reads two.

    Join all: final count 2
Recv obtains 80 before main prints the first line. Each counter worker acquires exclusive access and increments once. Joining both workers establishes their completion; the final lock then reads two. Their internal completion order is unspecified.

Channels, Arc and Mutex explained

A sender’s send transfers a message to the channel. Recv waits for a message or reports that the channel is disconnected. Arc::clone shares ownership of the same mutex. Lock returns a guard; dropping that guard releases the lock. Arc alone does not make arbitrary mutation safe.

Work through the Rust program

Save the complete source as main.rs in the Rust environment. No standard input is needed.

Rust 2024 · complete program

use std::{sync::{mpsc, Arc, Mutex}, thread};
fn main() {
  let (tx, rx) = mpsc::channel();
  let sender = thread::spawn(move || tx.send(80).expect("receiver exists"));
  println!("Message: {}", rx.recv().expect("sender sends"));
  sender.join().expect("sender finishes");
  let count = Arc::new(Mutex::new(0));
  let mut workers = Vec::new();
  for _ in 0..2 {
    let shared = Arc::clone(&count);
    workers.push(thread::spawn(move || { *shared.lock().expect("not poisoned") += 1; }));
  }
  for worker in workers { worker.join().expect("worker finishes"); }
  println!("Count: {}", *count.lock().expect("not poisoned"));
}

Expected output

Message: 80
Count: 2

Follow the execution

Recv obtains 80 before main prints the first line. Each counter worker acquires exclusive access and increments once. Joining both workers establishes their completion; the final lock then reads two. Their internal completion order is unspecified.

Try the complete program in the Rust compiler. For tests, Cargo commands and local files, use the specified local environment.

Try a small variation

Your task: Would Arc without a Mutex make unsynchronized shared mutation safe?

Rust 2024 · complete program

use std::{sync::{mpsc, Arc, Mutex}, thread};
fn main() {
  let (tx, rx) = mpsc::channel();
  let sender = thread::spawn(move || tx.send(80).expect("receiver exists"));
  println!("Message: {}", rx.recv().expect("sender sends"));
  sender.join().expect("sender finishes");
  let count = Arc::new(Mutex::new(0));
  let mut workers = Vec::new();
  for _ in 0..2 {
    let shared = Arc::clone(&count);
    workers.push(thread::spawn(move || { *shared.lock().expect("not poisoned") += 1; }));
  }
  for worker in workers { worker.join().expect("worker finishes"); }
  println!("Count: {}", *count.lock().expect("not poisoned"));
}

Worked answer

No. Arc manages shared ownership, while the Mutex provides the access synchronization here. Waiting for workers and protecting mutations solve separate problems.

Mistakes and limits to recognize

Mutex locking can deadlock, and poisoning needs a deliberate recovery decision. Keep locked work short and avoid holding a guard across operations that may wait on another lock. Channels can block or disconnect; they are not automatically bounded queues or durable delivery systems.

API details: official Rust documentation for this boundary.

Check your understanding

Would Arc without a Mutex make unsynchronized shared mutation safe?
Choose one answer. You can try again.

Answer and explanation

No.

No. Arc manages shared ownership, while the Mutex provides the access synchronization here. Waiting for workers and protecting mutations solve separate problems.

Apply the rule

Why both protect increments with Mutex and join the workers?
Choose one answer. You can try again.

Answer and explanation

Mutex protects overlapping updates; join establishes worker completion.

Safe access and waiting for completion are different requirements.

Take the idea into your next program

No. Arc manages shared ownership, while the Mutex provides the access synchronization here. Waiting for workers and protecting mutations solve separate problems. Mutex locking can deadlock, and poisoning needs a deliberate recovery decision.

Further reading: the official Rust Book on channels, arc and mutex.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Async functions and lazy futures →