3

I want to some work on a vector shared by multiple threads but I don't want to use a Mutex because it is not wait-free.

The code below is written as I would in C.

#![feature(core_intrinsics, ptr_internals)]

use std::intrinsics::atomic_xadd_rel;
use std::ptr::Unique;
use std::thread::spawn;

fn main() {
    let mut data = [0; 8];
    let mut pool = Vec::with_capacity(8);
    for index in 0..8 {
        let data_ptr = Unique::new(data.as_mut_ptr());
        pool.push(spawn(move || {
            println!("Thread {} -> {}", index, unsafe {
                atomic_xadd_rel(
                    data_ptr
                        .unwrap()
                        .as_ptr()
                        .add(if index % 2 != 0 { index - 1 } else { index }),
                    1,
                )
            });
        }));
    }
    for work in pool {
        work.join().unwrap();
    }
    println!("Data {:?}", data);
}

I've also written the code using only the stable API:

use std::iter::repeat_with;
use std::sync::atomic::{AtomicUsize, Ordering::*};
use std::sync::Arc;
use std::thread::spawn;

fn main() {
    let data = Arc::new(
        repeat_with(|| AtomicUsize::new(0))
            .take(8)
            .collect::<Vec<_>>(),
    );
    let mut pool = Vec::with_capacity(8);
    for index in 0..8 {
        let data_clone = data.clone();
        pool.push(spawn(move || {
            let offset = index - (index % 2 != 0) as usize;
            println!(
                "Thread {} -> {}",
                index,
                data_clone[offset].fetch_add(1, Relaxed)
            );
        }));
    }
    for work in pool {
        work.join().unwrap();
    }
    println!("Data {:?}", data);
}

This code returns

Thread 0 -> 0
Thread 1 -> 1
Thread 3 -> 0
Thread 5 -> 1
Thread 7 -> 1
Thread 2 -> 1
Thread 6 -> 0
Thread 4 -> 0
Data [2, 0, 2, 0, 2, 0, 2, 0]

Is there is a proper way to do this in Rust?

I do not think this is a duplicate of How do I pass disjoint slices from a vector to different threads? because my vector / slice elements overlap between threads. In my sample, each odd index of the slice is incremented twice by two different threads.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
The_Server201
  • 31
  • 1
  • 5
  • 1
    Possible duplicate of [How do I pass disjoint slices from a vector to different threads?](https://stackoverflow.com/questions/33818141/how-do-i-pass-disjoint-slices-from-a-vector-to-different-threads) – Lucretiel Nov 22 '18 at 00:17

1 Answers1

2

Assuming that each thread has unique access to a particular element or sub-slice of your vector, this would be a case to use split_at (or one of the similar functions). split_at splits a mutable slice into two independent mutable slices; you can call it multiple times to split your slice into the correct number of segments, and pass each sub-slice to a separate thread.

The best way to pass the sub-slices to a thread would be to use something like the scoped threads in crossbeam.

Lucretiel
  • 3,145
  • 1
  • 24
  • 52