Rust Guide > Documentation > Concurrency > Arc

Introduction

In Rust, Arc stands for Atomic Reference Counting and is used for thread-safe reference counting. It allows you to share ownership of an immutable value across multiple threads. When the last reference to the value is dropped, the value is deallocated.

Using Arc

To use Arc, you need to import it from the std::sync module. You can create an Arc by using the Arc::new method. Cloning an Arc increases its reference count, and when all clones are dropped, the value is deallocated.

use std::sync::Arc;

fn main() {
    let value = Arc::new(5);
    let value_clone = Arc::clone(&value);

    println!("Value: {}", value);
    println!("Cloned Value: {}", value_clone);
}
// Output:
// Value: 5
// Cloned Value: 5

Key Methods

Below are some of the key methods exposed by the Arc class:

Arc::new

Creates a new Arc instance.

use std::sync::Arc;

fn main() {
    let value = Arc::new(10);
    println!("Value: {}", value);
}
// Output:
// Value: 10

Arc::clone

Clones the Arc, increasing the reference count.

use std::sync::Arc;

fn main() {
    let value = Arc::new(15);
    let value_clone = Arc::clone(&value);
    println!("Value: {}", value);
    println!("Cloned Value: {}", value_clone);
}
// Output:
// Value: 15
// Cloned Value: 15

Arc::strong_count

Returns the number of strong references to the Arc.

use std::sync::Arc;

fn main() {
    let value = Arc::new(20);
    let value_clone = Arc::clone(&value);
    println!("Reference Count: {}", Arc::strong_count(&value));
}
// Output:
// Reference Count: 2

Example Usage

Example 1: Basic Usage

use std::sync::Arc;

fn main() {
    let value = Arc::new(30);
    println!("Value: {}", value);
}
// Output:
// Value: 30

Example 2: Cloning Arc

use std::sync::Arc;

fn main() {
    let value = Arc::new(35);
    let value_clone = Arc::clone(&value);
    println!("Value: {}", value);
    println!("Cloned Value: {}", value_clone);
}
// Output:
// Value: 35
// Cloned Value: 35

Example 3: Reference Counting

use std::sync::Arc;

fn main() {
    let value = Arc::new(40);
    let value_clone1 = Arc::clone(&value);
    let value_clone2 = Arc::clone(&value);
    println!("Reference Count: {}", Arc::strong_count(&value));
}
// Output:
// Reference Count: 3

Example 4: Using Arc with Threads

use std::sync::Arc;
use std::thread;

fn main() {
    let value = Arc::new(50);
    let mut handles = vec![];

    for _ in 0..5 {
        let value_clone = Arc::clone(&value);
        let handle = thread::spawn(move || {
            println!("Value in thread: {}", value_clone);
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }
}
// Output (order may vary):
// Value in thread: 50
// Value in thread: 50
// Value in thread: 50
// Value in thread: 50
// Value in thread: 50

Example 5: Dropping Arc

use std::sync::Arc;

fn main() {
    let value = Arc::new(60);
    {
        let value_clone = Arc::clone(&value);
        println!("Reference Count: {}", Arc::strong_count(&value));
    } // value_clone goes out of scope here
    println!("Reference Count after drop: {}", Arc::strong_count(&value));
}
// Output:
// Reference Count: 2
// Reference Count after drop: 1

Considerations

  • Arc is only for sharing immutable data between threads. For mutable data, consider using Mutex or RwLock along with Arc.
  • Cloning an Arc is cheap, as it only increments the reference count.
  • When all Arc references are dropped, the inner value is deallocated.

See Also

  • Rc - Similar to Arc but not thread-safe.
  • Mutex - Used for sharing mutable data between threads.
  • RwLock - Allows multiple readers or a single writer.
  • RefCell - Allows for mutable borrowing checked at runtime.