2016-03-24 27 views
9

Poiché Rust non ha la capacità integrata di leggere da un file in modo non bloccante, devo generare un thread che legge il file /dev/input/fs0 per ottenere gli eventi del joystick. Supponiamo che il joystick non sia utilizzato (niente da leggere), quindi il thread di lettura è bloccato durante la lettura dal file.Come posso forzare la lettura di un thread bloccato da un file in Rust?

C'è un modo per il thread principale di forzare la lettura di blocco del thread di lettura per riprendere, quindi il thread di lettura potrebbe uscire in modo pulito?

In altre lingue, vorrei semplicemente chiudere il file nel thread principale. Ciò costringerebbe la lettura di blocco a riprendere. Ma non ho trovato un modo per farlo in Rust, perché la lettura richiede un riferimento mutevole al file.

+0

È 'mio' troppo pesante per questo utilizzo? – WiSaGaN

+0

@WiSaGaN MIO non gestisce espressamente l'I/O asincrono per i file. Una buona lettura sullo [sfondo del file I/O asincrono] (http://blog.libtorrent.org/2012/10/asynchronous-disk-io/). – Shepmaster

+1

@Shepmaster OP non ha bisogno di IO asincrono come sembra. L'IO non bloccante può essere ottenuto usando 'mio' con un' RawFd' 'Evented'. – WiSaGaN

risposta

1

L'idea è di chiamare File::read solo quando sono disponibili i dati. Se non ci sono dati disponibili, controlliamo un flag per vedere se il thread principale ha richiesto di fermarsi. Altrimenti, attendi di nuovo.

Ecco un esempio utilizzando nonblock cassa:

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

Ecco un esempio utilizzando poll legame di nix cassa. La funzione pool attende (con timeout) eventi specifici:

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!"); 

}