Каков стандартный способ получить поток Rust от операций блокировки?
Исходя из Java, я привык к идиомам по типу
while (true) {
try {
someBlockingOperation();
} catch (InterruptedException e) {
Thread.currentThread.interrupt(); // re-set the interrupted flag
cleanup(); // whatever is necessary
break;
}
}
Насколько я знаю, это работает во всем JDK для всего, что может блокировать, например, чтение из файлов, из сокетов, из очереди и даже для Thread.sleep()
,
Читая о том, как это делается в Rust, я нахожу множество, казалось бы, специальных решений, упомянутых как mio
, tokio
, Я также нахожу ErrorKind::Interrupted
и пытался получить это ErrorKind
с отправкой SIGINT
в нить, но нить, кажется, сразу же умирает, не оставляя (назад) след.
Вот код, который я использовал (примечание: еще не очень хорошо разбирался в Rust, поэтому он может выглядеть немного странно, но он работает):
use std::io;
use std::io::Read;
use std::thread;
pub fn main() {
let sub_thread = thread::spawn(|| {
let mut buffer = [0; 10];
loop {
let d = io::stdin().read(&mut buffer);
println!("{:?}", d);
let n = d.unwrap();
if n == 0 {
break;
}
println!("-> {:?}", &buffer[0..n]);
}
});
sub_thread.join().unwrap();
}
Под "операциями блокировки" я имею в виду:
- спать
- сокет IO
- файл IO
- IO очереди (еще не уверен, где находятся очереди в Rust)
Каковы будут соответствующие средства для передачи сообщения потоку, как Thread.interrupt()
на Яве, что пора собираться и идти домой?
1 ответ
Там нет такой вещи. Блокировка означает блокировку.
Вместо этого вы сознательно используете неблокирующие инструменты. Вот где приходят библиотеки, такие как mio или futures - они обрабатывают архитектуру склеивания всех этих неблокирующих, асинхронных частей.
catch (InterruptedException e)
Ржавчина не имеет исключений. Если вы ожидаете обработать случай сбоя, это лучше представить с Result
,
Thread.interrupt()
На самом деле это не делает ничего, кроме установки флага в потоке, который может проверить какой-то код, а затем вывести исключение. Вы можете построить такую же структуру самостоятельно. Одна простая реализация:
use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread,
time::Duration,
};
fn main() {
let please_stop = Arc::new(AtomicBool::new(false));
let t = thread::spawn({
let should_i_stop = please_stop.clone();
move || {
while !should_i_stop.load(Ordering::SeqCst) {
thread::sleep(Duration::from_millis(100));
println!("Sleeping");
}
}
});
thread::sleep(Duration::from_secs(1));
please_stop.store(true, Ordering::SeqCst);
t.join().unwrap();
}
Спать
Насколько я знаю, нет никакого способа прервать. В документации даже сказано:
На платформах Unix эта функция не будет возвращаться раньше из-за сигнала
Гнездо IO
Вы переводите сокет в неблокирующий режим, используя такие методы, как set_nonblocking
а затем обрабатывать ErrorKind::WouldBlock
,
Файл IO
На самом деле не существует хорошего кроссплатформенного способа выполнения асинхронного ввода-вывода файлов. Большинство реализаций раскручивают пул потоков и выполняют там блокирующие операции, отправляя данные поверх чего-то, что делает неблокирующим.
Очередь IO
Возможно, вы имеете в виду что-то вроде канала MPSC, и в этом случае вы будете использовать такие инструменты, как try_recv
,
Смотрите также: