编者注:此代码示例来自1.0之前的Rust版本,它使用的代码在Rust 1.0中不存在.一些答案已经更新,以回答更新版本的Rust的核心问题.
我正在尝试使用创建内存映射文件std::os::MemoryMap.目前的方法如下:
use std::os;
use std::ptr;
use std::old_io as io;
use std::os::unix::prelude::AsRawFd;
use std::os::MapOption;
let path = Path::new("test.mmap");
let f = match io::File::open_mode(&path, io::Open, io::ReadWrite) {
Ok(f) => f,
Err(err) => panic!("Could not open file: {}", err),
};
let mmap_opts = &[
MapOption::MapReadable,
MapOption::MapWritable,
MapOption::MapFd(f.as_raw_fd())
];
let mmap = match os::MemoryMap::new(1024*1024, mmap_opts) {
Ok(mmap) => {
println!("Successfully created the mmap: {}", mmap.len());
mmap
}
Err(err) => panic!("Could not read the mmap: {}", err),
};
unsafe {
let data = mmap.data();
if data.is_null() {
panic!("Could not access data from memory mapped file")
}
let src = "Hello!";
ptr::copy_memory(data, src.as_ptr(), src.as_bytes().len());
}
Run Code Online (Sandbox Code Playgroud)
这个程序失败了
Process didn't exit successfully: `target/mmap` (status=4)
Run Code Online (Sandbox Code Playgroud)
在ptr::copy_memory对数据进行呼叫或任何其他操作时.
MemoryMap?MemoryMap在Rust中使用的正确方法是什么?She*_*ter 16
真正的答案是使用提供此功能的箱子,理想情况是以跨平台的方式.
extern crate memmap;
use std::{
fs::OpenOptions,
io::{Seek, SeekFrom, Write},
};
const SIZE: u64 = 1024 * 1024;
fn main() {
let src = "Hello!";
let mut f = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open("test.mmap")
.expect("Unable to open file");
// Allocate space in the file first
f.seek(SeekFrom::Start(SIZE)).unwrap();
f.write_all(&[0]).unwrap();
f.seek(SeekFrom::Start(0)).unwrap();
let mut data = unsafe {
memmap::MmapOptions::new()
.map_mut(&f)
.expect("Could not access data from memory mapped file")
};
data[..src.len()].copy_from_slice(src.as_bytes());
}
Run Code Online (Sandbox Code Playgroud)
请注意,此代码仍可能导致未定义的行为.由于切片由文件支持,因此文件的内容(以及切片)可能会从Rust程序的外部更改,从而打破了unsafe块应该保留的不变量.程序员需要确保文件在地图生命周期内不会发生变化.不幸的是,箱子本身并没有提供太多帮助来防止这种情况发生,甚至没有任何文件警告用户.
如果您希望使用较低级别的系统调用,则缺少两个主要部分:
mmap 不会自己分配任何空间,因此您需要在文件中设置一些空间.没有这个,我Illegal instruction: 4在macOS上运行时会得到.
MemoryMap(默认情况下)是私有的,因此您需要将映射标记为公共,以便将更改写回文件(我假设您希望保存写入).如果没有这个,代码就会运行,但文件永远不会改变.
这是一个适合我的版本:
extern crate libc;
use std::{
fs::OpenOptions,
io::{Seek, SeekFrom, Write},
os::unix::prelude::AsRawFd,
ptr,
};
fn main() {
let src = "Hello!";
let size = 1024 * 1024;
let mut f = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open("test.mmap")
.expect("Unable to open file");
// Allocate space in the file first
f.seek(SeekFrom::Start(size as u64)).unwrap();
f.write_all(&[0]).unwrap();
f.seek(SeekFrom::Start(0)).unwrap();
// This refers to the `File` but doesn't use lifetimes to indicate
// that. This is very dangerous, and you need to be careful.
unsafe {
let data = libc::mmap(
/* addr: */ ptr::null_mut(),
/* len: */ size,
/* prot: */ libc::PROT_READ | libc::PROT_WRITE,
// Then make the mapping *public* so it is written back to the file
/* flags: */ libc::MAP_SHARED,
/* fd: */ f.as_raw_fd(),
/* offset: */ 0,
) as *mut u8;
if data.is_null() {
panic!("Could not access data from memory mapped file")
}
ptr::copy_nonoverlapping(src.as_ptr(), data, src.len());
}
}
Run Code Online (Sandbox Code Playgroud)
小智 8
最新版本:
use std::ptr;
use std::fs;
use std::io::{Write, SeekFrom, Seek};
use std::os::unix::prelude::AsRawFd;
use mmap::{MemoryMap, MapOption};
// from crates.io
extern crate mmap;
extern crate libc;
fn main() {
let size: usize = 1024*1024;
let mut f = fs::OpenOptions::new().read(true)
.write(true)
.create(true)
.open("test.mmap")
.unwrap();
// Allocate space in the file first
f.seek(SeekFrom::Start(size as u64)).unwrap();
f.write_all(&[0]).unwrap();
f.seek(SeekFrom::Start(0)).unwrap();
let mmap_opts = &[
// Then make the mapping *public* so it is written back to the file
MapOption::MapNonStandardFlags(libc::consts::os::posix88::MAP_SHARED),
MapOption::MapReadable,
MapOption::MapWritable,
MapOption::MapFd(f.as_raw_fd()),
];
let mmap = MemoryMap::new(size, mmap_opts).unwrap();
let data = mmap.data();
if data.is_null() {
panic!("Could not access data from memory mapped file")
}
let src = "Hello!";
let src_data = src.as_bytes();
unsafe {
ptr::copy(src_data.as_ptr(), data, src_data.len());
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5943 次 |
| 最近记录: |