Closed
Description
I have multiple threads reading from a std::fs::File
handle. The existing Read Trait for File is not so nice in this case because of the mutability&mut File
. I created the non-mutable platform independent version from the plattform specific counterparts like below.
It would be nice to have this in the standard library.
#[cfg(any(windows))]
fn load_exact_bytes_at(buffer: &mut Vec<u8>, file: &File, offset: u64) {
use std::os::windows::fs::FileExt;
let mut data_read = 0;
while data_read < buffer.len() {
data_read += file.seek_read(buffer, offset).unwrap();
}
}
#[cfg(any(unix))]
fn load_exact_bytes_at(buffer: &mut Vec<u8>, file: &File, offset: u64) {
use std::os::unix::fs::FileExt;
let mut data_read = 0;
while data_read < buffer.len() {
data_read += file.read_at(buffer, offset).unwrap();
}
}
Activity
ranma42 commentedon Jan 6, 2018
Assuming that
seek_read
actually changes the current position of the file, I am afraid the missingmut
ability on theself
argument was overlooked.PSeitz commentedon Jan 6, 2018
@tbu- mentions only WriteFile here: #35704 (comment), but the
seek_write
version is not&mut
hanna-kruppe commentedon Jan 6, 2018
&File
implementsRead
so usingFile
methods from multiple threads is perfectly possible: They only need a mutable reference to the&File
, of which each thread can have a separate copy.PSeitz commentedon Jan 6, 2018
I know this is possible, but the unnecessary(?) mut complicates things (a lot in my case, without the plattform specific implementation).
tbu- commentedon Jan 6, 2018
Here's how to read from a immutable reference to a file:
Your implementation of
load_exact_bytes_at
(and the write counterpart) is buggy if the operating system returns with a short read (write), or if the operating system returns an error.EDIT: Removed the
&mut
in(&mut file).read(&mut buf)?
.hanna-kruppe commentedon Jan 6, 2018
@PSeitz Complicates how? You already have a
&File
. You just need to add amut
to the binding (thefile: &File
parameter or local) that you want to call the method on. No function signature or type change, no lifetime annotations change, etc., just a simple three letters for (at most) everyRead
method call. That doesn't seem like a significant burden, and especially not like one big enough to introduce a whole new API.PSeitz commentedon Jan 6, 2018
Okay, I thought a
&mut
was required. In this case, I don't understand how e.g. that snippet below works. Is this a race condition? Does Rust protect me from race conditions on a single file handle?hanna-kruppe commentedon Jan 6, 2018
A
&mut self
is required, but since the impl is for&File
, the self parameter is a&mut &File
.The file I/O is racy, yes. Rust does not provide guaranteed protection from "logical races", just from data races. The operating systems' I/O operations are data-race-free even when multiple threads work on the same file, but even a single I/O operation is rarely atomic (e.g., a read might get interrupted). Multiple separate operations (such as the
seek
andread_exact
in your example) can't be atomic without external synchronization. Therefore, working on the same file from multiple threads is generally very wrong (unless there's other synchronization between the threads).PSeitz commentedon Jan 6, 2018
Do you mean file or std::fs::File? Do you refer to that read-only scenario?
I thought read-only with multiple file handles should be no problem.
Multiple threads with read and writes are of course bad without extra synchronization.
It would be nice if the API was designed, to protect from races on a single std::fs::File.
hanna-kruppe commentedon Jan 6, 2018
I meant the
std::fs::File
type.A
std::fs::File
object has a current read position, which is changed any time you read or seek.Yes (though again, just a race, not a data race).
Maybe, but backwards compatibility prevents us from changing this.
Can this issue be closed now? It seems the proposed API is no longer needed. If you have any further questions, I'd direct you to http://users.rust-lang.org/ or other forums.