// Example 109: Arc<T> for Thread-Safe Sharing
//
// Arc = Atomic Reference Counting. Like Rc but thread-safe.
// Use Arc when sharing immutable data across threads.
use std::sync::Arc;
use std::thread;
// Approach 1: Shared data across threads
fn approach1() {
let data: Arc<Vec<i32>> = Arc::new((1..=100).collect());
let data1 = Arc::clone(&data);
let handle1 = thread::spawn(move || {
data1[..50].iter().sum::<i32>()
});
let data2 = Arc::clone(&data);
let handle2 = thread::spawn(move || {
data2[50..].iter().sum::<i32>()
});
let sum1 = handle1.join().unwrap();
let sum2 = handle2.join().unwrap();
let total = sum1 + sum2;
assert_eq!(total, 5050);
println!("Total: {}", total);
}
// Approach 2: Map-reduce with threads
fn parallel_map_reduce<T, R, F, G>(data: Vec<T>, mapper: F, reducer: G, init: R) -> R
where
T: Send + 'static,
R: Send + 'static + Copy,
F: Fn(T) -> R + Send + Sync + 'static,
G: Fn(R, R) -> R,
{
let mapper = Arc::new(mapper);
let handles: Vec<_> = data.into_iter().map(|item| {
let mapper = Arc::clone(&mapper);
thread::spawn(move || mapper(item))
}).collect();
let mut result = init;
for h in handles {
result = reducer(result, h.join().unwrap());
}
result
}
fn approach2() {
let data = vec![1, 2, 3, 4, 5];
let result = parallel_map_reduce(data, |x| x * x, |a, b| a + b, 0);
assert_eq!(result, 55);
println!("Sum of squares: {}", result);
}
// Approach 3: Shared config across worker threads
fn approach3() {
let texts = Arc::new(vec![
"hello world".to_string(),
"foo bar baz".to_string(),
"one".to_string(),
]);
let mut handles = vec![];
for i in 0..texts.len() {
let texts = Arc::clone(&texts);
handles.push(thread::spawn(move || {
texts[i].split_whitespace().count()
}));
}
let total: usize = handles.into_iter()
.map(|h| h.join().unwrap())
.sum();
assert_eq!(total, 6);
println!("Total words: {}", total);
}
fn main() {
println!("=== Approach 1: Parallel Sum ===");
approach1();
println!("\n=== Approach 2: Map-Reduce ===");
approach2();
println!("\n=== Approach 3: Shared Config ===");
approach3();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arc_across_threads() {
let data = Arc::new(42);
let data2 = Arc::clone(&data);
let handle = thread::spawn(move || *data2);
assert_eq!(handle.join().unwrap(), 42);
}
#[test]
fn test_arc_strong_count() {
let a = Arc::new("hello");
let b = Arc::clone(&a);
assert_eq!(Arc::strong_count(&a), 2);
drop(b);
assert_eq!(Arc::strong_count(&a), 1);
}
#[test]
fn test_parallel_map_reduce() {
let result = parallel_map_reduce(vec![1, 2, 3], |x| x * 2, |a, b| a + b, 0);
assert_eq!(result, 12);
}
#[test]
fn test_shared_vec_threads() {
let v = Arc::new(vec![10, 20, 30]);
let handles: Vec<_> = (0..3).map(|i| {
let v = Arc::clone(&v);
thread::spawn(move || v[i])
}).collect();
let sum: i32 = handles.into_iter().map(|h| h.join().unwrap()).sum();
assert_eq!(sum, 60);
}
}
(* Example 109: Arc<T> — Thread-Safe Sharing *)
(* OCaml's GC is thread-safe by default. Sharing data between
threads (via Domain in OCaml 5) just works. *)
(* Approach 1: Shared immutable data across "workers" *)
let process_chunk data start len =
let sum = ref 0 in
for i = start to start + len - 1 do
sum := !sum + data.(i)
done;
!sum
let approach1 () =
let data = Array.init 100 (fun i -> i + 1) in
let sum1 = process_chunk data 0 50 in
let sum2 = process_chunk data 50 50 in
let total = sum1 + sum2 in
assert (total = 5050);
Printf.printf "Total: %d\n" total
(* Approach 2: Map-reduce pattern *)
let map_reduce mapper reducer init data =
let mapped = List.map mapper data in
List.fold_left reducer init mapped
let approach2 () =
let data = [1; 2; 3; 4; 5] in
let result = map_reduce (fun x -> x * x) ( + ) 0 data in
assert (result = 55);
Printf.printf "Sum of squares: %d\n" result
(* Approach 3: Parallel word count simulation *)
let count_words text =
let words = String.split_on_char ' ' text in
List.length (List.filter (fun w -> String.length w > 0) words)
let approach3 () =
let texts = ["hello world"; "foo bar baz"; "one"] in
let counts = List.map count_words texts in
let total = List.fold_left ( + ) 0 counts in
assert (total = 6);
Printf.printf "Total words: %d\n" total
let () =
approach1 ();
approach2 ();
approach3 ();
Printf.printf "✓ All tests passed\n"