Parallel Computing in Rust and C++ part 1

Parallelism in Rust usually means one of three things:

  1. Data-parallel CPU work (split work across cores)
  2. Task parallelism (run independent CPU tasks concurrently)
  3. Async concurrency (lots of I/O, not CPU parallel by default)

When making things go parallel, there are following things to consider. Safe parallel code comes from being explicit about what is shared, who owns it, and how threads/tasks coordinate.

Here’s a practical checklist programmers should run through.

Safe Parallel Computing Check-list:

1) Identify shared state and decide how it’s protected

Parallel bugs mostly come from shared mutable state.

  • Best option: avoid sharing by design (copy data, partition data, message passing).
  • If you must share, pick one:

Immutability (share read-only data freely)

Ownership / single-writer (only one thread can mutate; others read snapshots)

Synchronization (locks, atomics, channels)

Rust code example:

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    for i in 0..4 {
        let tx = tx.clone();
        thread::spawn(move || {
            // each worker owns its local state
            tx.send(i * i).unwrap();
        });
    }
    drop(tx); // close channel

    let sum: i32 = rx.iter().sum();
    println!("sum={sum}");
}
std::thread
Rust’s native OS-thread API.
It answers:
“How do I start another thread of execution?”

example usage:
use std::thread;

fn main() {
let v = vec![1, 2, 3];

let h = thread::spawn(move || {
println!("{:?}", v); // ✅ owned inside thread
});

h.join().unwrap();
}

spawn return a join handle, join() is to wait the thread finish. if join is not used here, main function may finish before the thread finish, then the process finish and the thread is killed.
v is a variable belongs to main, the thread needs to claim the ownership of v, so move is necessary.

The same thing in c++:
#include <thread>
#include <vector>
#include <iostream>
#include <utility>

void worker(std::vector<int> v) {
std::cout << v.size() << "\n";
}

int main() {
std::vector<int> v{1, 2, 3};

std::thread t(worker, std::move(v)); // moves v into worker argument
t.join();
}


move is not enforced here, might crash in runtime.
This is the "memory lifetime safety problem exposed by concurrency---when you pass data to a thread without transferring ownership"
one might use references or pointers, this might be use-after-free problem.
The key principle is You must ensure the thread owns the data OR the data outlives the thread.
by move, or copy the data, or guarantee lifetime manually.

Leave a Reply

Your email address will not be published. Required fields are marked *