如何在Rust中使用不同的线程向文件写入数据?

6

我正在尝试找到一种方法,用于在不同线程中锁定文件的写入。正确的方式是什么? 我不想因为性能问题每次需要写入时都打开和关闭文件。

我尝试过的代码如下:

use std::{fs, mem, thread};
use std::os::unix::prelude::FileExt;
use std::sync::{Arc, Mutex};


const COUNT: usize = 1000;


fn main() {
    let file: fs::File = fs::File::create("foo.txt").unwrap();

    let v: [u32; COUNT] = [6; COUNT];

    let counter = Arc::new(Mutex::new(0));

    let mut threads = Vec::new();
    for _ in 0..COUNT {
        let counter = Arc::clone(&counter);

        let thread = thread::spawn(move || {
            let mut i = counter.lock().unwrap();

            let offset = (mem::size_of::<u32>() * (*i)) as u64;
            let bytes = unsafe { mem::transmute::<u32, [u8; 4]>(v[*i]) };
            file.write_all_at(&bytes, offset).unwrap();

            *i += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }
}

这会导致错误:

move occurs because `file` has type `std::fs::File`, which does not implement the `Copy` trait

据我理解,文件对象在线程之间无法轻松共享。我猜想,在处理此问题的整个方法方面,我可能做错了什么。那么,在Rust中从不同的线程写入文件的正确方式是什么?

只需像为 counter 一样为 file 创建另一个 Arc<Mutex> 即可。 - Aplet123
或者,您可以使用 Vec<u8>,然后可变地借用线程所需的部分,并最终使用 file.write_all(&vec) 写入文件。 - vallentin
1个回答

8

您可以使用 ArcMutex 将文件包装起来,这样它就可以在线程之间共享,并且一次只能被一个线程更改:

fn main() {
    let file = Arc::new(Mutex::new(File::create("foo.txt").unwrap()));

    let v: [u32; COUNT] = [6; COUNT];

    let counter = Arc::new(Mutex::new(0));

    let mut threads = Vec::new();
    for _ in 0..COUNT {
        let counter = Arc::clone(&counter);
        let file = Arc::clone(&file);

        let thread = thread::spawn(move || {
            let mut i = counter.lock().unwrap();
            let file = file.lock().unwrap();

            let offset = (mem::size_of::<u32>() * (*i)) as u64;
            let bytes = unsafe { mem::transmute::<u32, [u8; 4]>(v[*i]) };
            file.write_all_at(&bytes, offset).unwrap();

            *i += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }
}

注意,std::os::unix::fs::FileExt中的读写方法需要对self进行不可变引用。这意味着上面的代码如果没有Mutex也会编译通过,因为并发由操作系统内核管理。但是,由于多个线程可能同时尝试写入文件,结果是不确定的,这可能不是您想要的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接