2015-06-18 2 views
9

Вроде бы общие идиомы в Русте порождалась нитью для блокировки ввода-вывода, так что вы можете использовать неблокирующие каналы:Как я могу надежно очистить потоки ржавчины, выполняя блокировку IO?

use std::sync::mpsc::channel; 
use std::thread; 
use std::net::TcpListener; 

fn main() { 
    let (accept_tx, accept_rx) = channel(); 

    let listener_thread = thread::spawn(move || { 
     let listener = TcpListener::bind(":::0").unwrap(); 
     for client in listener.incoming() { 
      if let Err(_) = accept_tx.send(client.unwrap()) { 
       break; 
      } 
     } 
    }); 
} 

Проблема, присоединяясь темами, как это зависит от породившей нити «реализация "что приемный конец канала уронили (т.е., вызов send(..) возвращается Err(_)):

drop(accept_rx); 
listener_thread.join(); // blocks until listener thread reaches accept_tx.send(..) 

Вы можете сделать фиктивные соединения для TcpListener с, и отключение TcpStream сек через клона, но они, кажется, как на самом деле Hacky способы очистки таких читает, и в его нынешнем виде я даже не знаю об ошибке hack, чтобы вызвать блокировку потока при чтении от stdin.

Как я могу очистить такие темы, или моя архитектура просто не так?

+3

Общий шаблон для потоков, которые невозможно очистить с надежностью, - это уведомить их о необходимости очистки, просто дать им возможность работать и убедиться, что они больше не производят побочных эффектов. Для TcpListener это неприемлемо, но часто для исходящих запросов или операций с файлами. – usr

+1

@usr Да, но я ищу решение для ржавчины. (Мне кажется, это не обязательно подходит для этой формы). Я задал этот вопрос, потому что мне не удалось найти способ использования текущего (безопасного) API. – sleeparrow

+1

http://www.rust-lang.org/ – sleeparrow

ответ

-1

tldr; Фиктивная связь может быть самым простым способом.

(я предполагаю, что Linux в качестве ОС.)

listener.incoming() будем называть Признавайте() на TcpListener в .next() метод и нить будет застрял в принять вызов к Операционные системы. Он может, насколько мне известно, только добровольно возвращаться в результате попытки подключения или сигнала или если сокет установлен неблокированным.

Обработка сигналов, похоже, не поддерживается стандартными библиотеками ржавчины.

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

Альтернативой может быть использование mio, поскольку оно обеспечивает цикл событий. Вы могли бы либо адаптировать все ваше приложение к циклу событий, и не нуждаться в делать потоки, или вы могли бы использовать цикл событий для каждого потока, который мог бы блокировать и позволить ему прослушивать дополнительный канал, чтобы вы могли его разбудить что он может закрыть себя. Первый, возможно, не выполнит больше, в зависимости от того, как много кода у вас уже есть, а второй - переполнения.

+0

-1. Большая часть этого упоминалась как нежелательная в моем вопросе. Ящик 'mio' является действительным предложением, но он еще не поддерживает Windows. Я также уверен, что вы не можете просто добавить дополнительную «трубу» (канал?) Для потоков, чтобы прослушивать прерывания; они блокируют вызовы 'read'. Если вы считаете, что есть способ сделать это, как вы описали, просьба привести пример. – sleeparrow

+0

Я не знаю, как ситуация на окнах. Но в linux и многих других * nixes существуют такие механизмы, как epoll, kqueue и select, где вы регистрируете файловый дескриптор и получаете woken и уведомлены, если есть какие-то даже в любом из этих файловых дескрипторов. Труба - это просто пара дескрипторов файлов, там вы можете писать в одном и читать на другом. Сторона считывания будет перенесена в поток для очистки, и сторона записи останется с управляющей нитью, чтобы она могла вызывать бодрствование. Если это вам полезно, я могу сделать пример, используя ящик nix. Но это не будет работать на w. –

+0

Вопрос не в том, «как я могу использовать mutliplex streams in Rust?», А скорее «как я могу надежно и в целом очистить потоки, выполняющие блокировку ввода-вывода в Rust?». – sleeparrow

1

Просто невозможно безопасно отменить поток в Windows или Linux/Unix/POSIX, поэтому он недоступен в стандартной библиотеке Rust.

Here is an internals discussion about it.

Есть много неизвестных, которые возникают из-за принудительного отмены потоков. Это может стать действительно грязным. Кроме того, комбинация потоков и блокировки ввода-вывода всегда будет сталкиваться с этой проблемой: вам нужно, чтобы каждый блокирующий вызов ввода-вывода имел тайм-ауты, чтобы даже иметь возможность быть прерываемым надежно. Если не удается написать асинхронный код, нужно либо использовать процессы (которые имеют определенную границу и могут быть принудительно завершены ОС, но, очевидно, имеют более тяжелый вес и проблемы с совместным использованием данных) или неблокирующий ввод-вывод, который будет переместите свой поток обратно в цикл событий, который прерывается.

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