Каков стандартный способ получить поток Rust от операций блокировки? - PullRequest
0 голосов
/ 23 сентября 2018

Исходя из 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();
}

Под "операциями блокировки" я имею в виду:

  • sleep
  • сокет IO
  • file IO
  • IO очереди (еще не уверен, где находятся очереди в Rust)

Что бызначит означает сигнализировать потоку, как Thread.interrupt() в Java, что пора собираться и идти домой?

1 Ответ

0 голосов
/ 23 сентября 2018

Нет такой вещи.Блокировка означает блокировку.

Вместо этого вы сознательно используете инструменты, неблокирующие .Вот где приходят такие библиотеки, как mio или futures - они обрабатывают архитектуру склеивания всех этих неблокирующих асинхронных частей.

catch (InterruptedException e)

Rust ненет исключенийЕсли вы ожидаете обработать случай сбоя, лучше представить его с помощью 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 эта функция не будет рано возвращаться из-за сигнала

Socket IO

Вы переводите сокет в неблокирующий режим, используя методы, такие как set_nonblocking, а затем обрабатываете ErrorKind::WouldBlock.

File IO

Там нетдействительно хороший кроссплатформенный способ выполнения асинхронного файлового ввода-вывода.Большинство реализаций раскручивают пул потоков и выполняют там операции блокировки, отправляя данные поверх чего-то, что делает неблокирующим.

Очередь ввода-вывода

Возможно, вы имеете в виду что-то вроде канала MPSC , в этом случае вы будете использовать такие инструменты, как try_recv.

См. Также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...