如何将不相交的切片从向量传递到不同的线程? [英] How do I pass disjoint slices from a vector to different threads?

查看:31
本文介绍了如何将不相交的切片从向量传递到不同的线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to Rust, and struggling to deal with all those wrapper types in Rust. I am trying to write code that is semantically equal to the following C code. The code tries to create a big table for book keeping, but will divide the big table so that every thread will only access their local small slices of that table. The big table will not be accessed unless other threads quit and no longer access their own slice.

#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]);
}

我如何使用 Rust 的类型和所有权来实现这一点?

How do I use Rust's types and ownership to achieve this?

推荐答案

让我们从代码开始:

// 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;
    }
}

需要注意的一点是,这需要 crossbeam 板条箱.Rust使用有一个类似的作用域"结构,但在 1.0 之前正确发现了一个健全的漏洞,因此它被弃用,没有时间替换它.crossbeam 基本上是替代品.

One thing to note is that this needs the crossbeam crate. Rust used to have a similar "scoped" construct, but a soundness hole was found right before 1.0, so it was deprecated with no time to replace it. crossbeam is basically the replacement.

Rust 让你在这里做的是表达这样一个想法,无论代码做什么,在对 crossbeam::scoped 的调用中创建的线程中没有 将幸存下来范围.因此,任何从外部借用的东西都会比线程活得更长.因此,线程可以自由地访问这些借用,而不必担心诸如比 table 定义的堆栈帧寿命更长的线程并在堆栈上乱写之类的事情.

What Rust lets you do here is express the idea that, whatever the code does, none of the threads created within the call to crossbeam::scoped will survive that scope. As such, anything borrowed from outside that scope will live longer than the threads. Thus, the threads can freely access those borrows without having to worry about things like, say, a thread outliving the stack frame that table is defined by and scribbling over the stack.

所以这应该或多或少地与 C 代码做同样的事情,尽管不用担心你可能错过了什么.:)

So this should do more or less the same thing as the C code, though without that nagging worry that you might have missed something. :)

最后,这里使用 scoped_threadpool 代替.唯一真正的实际区别是这允许我们控制使用多少线程.

Finally, here's the same thing using scoped_threadpool instead. The only real practical difference is that this allows us to control how many threads are used.

// 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;
    }
}

这篇关于如何将不相交的切片从向量传递到不同的线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆