2016-03-24 6 views
9

Weil Rust nicht über die eingebaute Fähigkeit verfügt, non-blocking aus einer Datei zu lesen, muss ich einen Thread erzeugen, der die Datei /dev/input/fs0 liest, um Joystick-Ereignisse zu bekommen. Angenommen, der Joystick ist unbenutzt (nichts zu lesen), so dass der Lese-Thread während des Lesens aus der Datei blockiert ist.Wie kann ich einen Thread, der das Lesen von einer Datei blockiert, in Rust fortsetzen?

Gibt es eine Möglichkeit für den Haupt-Thread, das blockierende Lesen des Lese-Threads zu erzwingen, damit der Lese-Thread sauber beendet wird?

In anderen Sprachen würde ich einfach die Datei im Hauptthread schließen. Dies würde das Fortsetzen des blockierenden Lesevorgangs erzwingen. Aber ich habe in Rust keinen Weg gefunden, dies zu tun, denn das Lesen erfordert einen veränderlichen Verweis auf die Datei.

+0

Ist 'Mio' zu schwer für diesen Zweck? – WiSaGaN

+0

@WiSaGaN MIO behandelt ausdrücklich nicht async IO für Dateien. Eine gute Lesung auf dem [Hintergrund der asynchronen Datei IO] (http://blog.libtorrent.org/2012/10/asynchronous-disk-io/). – Shepmaster

+1

@Shempmaster OP benötigt kein asynchrones IO, wie es scheint. Non-blocking IO kann erreicht werden, indem 'mio' mit einem' RawFd' 'Evented' verwendet wird. – WiSaGaN

Antwort

1

Die Idee ist, File::read nur aufzurufen, wenn Daten verfügbar sind. Wenn keine Daten verfügbar sind, überprüfen wir ein Flag, um zu sehen, ob der Haupt-Thread zum Stoppen aufgefordert wurde. Wenn nicht, warten Sie noch einmal.

Hier ist ein Beispiel unter Verwendung von nonblock Kiste:

extern crate nonblock; 

use std::fs::File; 
use std::sync::{Arc, Mutex}; 
use std::thread; 
use std::time::Duration; 

use nonblock::NonBlockingReader; 

fn main() { 
    let f = File::open("/dev/stdin").expect("open failed"); 
    let mut reader = NonBlockingReader::from_fd(f).expect("from_fd failed"); 

    let exit = Arc::new(Mutex::new(false)); 
    let texit = exit.clone(); 

    println!("start reading, type something and enter"); 

    thread::spawn(move || { 
     let mut buf: Vec<u8> = Vec::new(); 
     while !*texit.lock().unwrap() { 
      let s = reader.read_available(&mut buf).expect("io error"); 
      if s == 0 { 
       if reader.is_eof() { 
        println!("eof"); 
        break; 
       } 
      } else { 
       println!("read {:?}", buf); 
       buf.clear(); 
      } 
      thread::sleep(Duration::from_millis(200)); 
     } 
     println!("stop reading"); 
    }); 

    thread::sleep(Duration::from_secs(5)); 

    println!("closing file"); 
    *exit.lock().unwrap() = true; 

    thread::sleep(Duration::from_secs(2)); 
    println!("\"stop reading\" was printed before the main exit!"); 
} 

fn read_async<F>(file: File, fun: F) -> thread::JoinHandle<()> 
    where F: Send + 'static + Fn(&Vec<u8>) 
{ 
    let mut reader = NonBlockingReader::from_fd(file).expect("from_fd failed"); 
    let mut buf: Vec<u8> = Vec::new(); 
    thread::spawn(move || { 
     loop { 
      let s = reader.read_available(&mut buf).expect("io error"); 
      if s == 0 { 
       if reader.is_eof() { 
        break; 
       } 
      } else { 
       fun(&buf); 
       buf.clear(); 
      } 
      thread::sleep(Duration::from_millis(100)); 
     } 
    }) 
} 

Hier ist ein Beispiel unter Verwendung von poll von nix Kiste verbindlich. Die Funktion pool wartet (mit Timeout) auf bestimmte Ereignisse:

extern crate nix; 

use std::io::Read; 
use std::os::unix::io::AsRawFd; 
use std::sync::{Arc, Mutex}; 
use std::thread; 
use std::time::Duration; 

use nix::poll; 

fn main() { 
    let mut f = std::fs::File::open("/dev/stdin").expect("open failed"); 
    let mut pfd = poll::PollFd { 
     fd: f.as_raw_fd(), 
     events: poll::POLLIN, // is there input data? 
     revents: poll::EventFlags::empty(), 
    }; 

    let exit = Arc::new(Mutex::new(false)); 
    let texit = exit.clone(); 

    println!("start reading, type something and enter"); 

    thread::spawn(move || { 
     let timeout = 100; // millisecs 
     let mut s = unsafe { std::slice::from_raw_parts_mut(&mut pfd, 1) }; 
     let mut buffer = [0u8; 10]; 
     loop { 
      if poll::poll(&mut s, timeout).expect("poll failed") != 0 { 
       let s = f.read(&mut buffer).expect("read failed"); 
       println!("read {:?}", &buffer[..s]); 
      } 
      if *texit.lock().unwrap() { 
       break; 
      } 
     } 
     println!("stop reading"); 
    }); 

    thread::sleep(Duration::from_secs(5)); 

    println!("closing file"); 
    *exit.lock().unwrap() = true; 

    thread::sleep(Duration::from_secs(2)); 
    println!("\"stop reading\" was printed before the main exit!"); 

} 
Verwandte Themen