如何将不相交的切片从向量传递到不同的线程?

qin*_*oon 6 rust

我是Rust的新手,并努力处理Rust中的所有包装器类型.我试图编写在语义上等于以下C代码的代码.代码尝试创建一个用于簿记的大表,但是会分割大表,以便每个线程只访问该表的本地小片.除非其他线程退出并且不再访问自己的切片,否则不会访问大表.

#include <stdio.h>
#include <pthread.h>

void* write_slice(void* arg) {
    int* slice = (int*) arg;
    int i;
    for (i = 0; i < 10; i++)
        slice[i] = i;

    return NULL;
}

int main()
{
    int* table = (int*) malloc(100 * sizeof(int));
    int* slice[10];
    int i;
    for (i = 0; i < 10; i++) {
      slice[i] = table + i * 10;
    }

    // create pthread for each slice
    pthread_t p[10];
    for (i = 0; i < 10; i++)
        pthread_create(&p[i], NULL, write_slice, slice[i]);

    for (i = 0; i < 10; i++)
        pthread_join(p[i], NULL);

    for (i = 0; i < 100; i++)
        printf("%d,", table[i]);
}
Run Code Online (Sandbox Code Playgroud)

如何使用Rust的类型和所有权来实现此目的?

DK.*_*DK. 15

让我们从代码开始:

// cargo-deps: crossbeam="0.7.3"
extern crate crossbeam;

const CHUNKS: usize = 10;
const CHUNK_SIZE: usize = 10;

fn main() {
    let mut table = [0; CHUNKS * CHUNK_SIZE];

    // Scoped threads allow the compiler to prove that no threads will outlive
    // table (which would be bad).
    let _ = crossbeam::scope(|scope| {
        // Chop `table` into disjoint sub-slices.
        for slice in table.chunks_mut(CHUNK_SIZE) {
            // Spawn a thread operating on that subslice.
            scope.spawn(move |_| write_slice(slice));
        }
        // `crossbeam::scope` ensures that *all* spawned threads join before
        // returning control back from this closure.
    });

    // At this point, all threads have joined, and we have exclusive access to
    // `table` again.  Huzzah for 100% safe multi-threaded stack mutation!
    println!("{:?}", &table[..]);
}

fn write_slice(slice: &mut [i32]) {
    for (i, e) in slice.iter_mut().enumerate() {
        *e = i as i32;
    }
}
Run Code Online (Sandbox Code Playgroud)

有一点需要注意,这需要crossbeam箱子.拉斯特使用也有类似的"作用域"建设,而是一个稳健洞被发现 1.0之前,所以这是没有时间来更换过时. crossbeam基本上是替代品.

拉斯特什么让你在这里做的是表达的想法,不管代码的功能,没有调用中创建的线程来crossbeam::scoped将生存该范围.因此,从该范围之外借来的任何东西都会比线程更长寿.因此,线程可以自由地访问那些借用而不必担心诸如线程超出由堆栈table定义的堆栈帧并在堆栈上乱写的线程.

因此,这应该与C代码或多或少相同,尽管没有令人烦恼的担心你可能错过了一些东西.:)

最后,使用相同的东西scoped_threadpool.唯一真正的实际区别是,这允许我们控制使用的线程数.

// cargo-deps: scoped_threadpool="0.1.6"
extern crate scoped_threadpool;

const CHUNKS: usize = 10;
const CHUNK_SIZE: usize = 10;

fn main() {
    let mut table = [0; CHUNKS * CHUNK_SIZE];

    let mut pool = scoped_threadpool::Pool::new(CHUNKS as u32);

    pool.scoped(|scope| {
        for slice in table.chunks_mut(CHUNK_SIZE) {
            scope.execute(move || write_slice(slice));
        }
    });

    println!("{:?}", &table[..]);
}

fn write_slice(slice: &mut [i32]) {
    for (i, e) in slice.iter_mut().enumerate() {
        *e = i as i32;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Lucretiel:观察来自子线程的"我已完成"信号的主线程意味着它还可以看到其他写入*先前*对该信号的写入.是否存在明确的锁定无关紧要; 重要的是,两人同意他们都可以看到什么时间点.如果你不相信,你应该提出一个新问题:我不是专家,评论不适合这个. (2认同)