2015-02-09 4 views
3

Предисловие: Я сделал свое исследование и знаю, что это действительно не очень хорошая идея, и это не идиоматическая ржавчина. Полностью открыт для предложений по другим способам решения этой проблемы.Как создать глобальный изменяемый флаг состояния bool

Справочная информация: У меня есть консольное приложение, которое подключается к веб-узлу и после успешного подключения сервер отправляет сообщение «Подключено». У меня есть отправитель, а приемник - отдельные потоки, и все работает отлично. После вызова connect() цикл начинается и помещает запрос в терминал, сигнализируя, что приложение готово для приема ввода от пользователя.

Проблема: Проблема в том, что текущий поток выполнения вызывает соединение, а затем сразу отображает приглашение, а затем приложение получает сообщение от сервера, в котором указано, что оно подключено.

Как бы решить эту проблема в высокоуровневых языках: Поместите глобальный BOOL (мы будем называть его ready) и после того, как приложение «готов», а затем отобразить подсказку.

Как я думаю, что это может выглядеть в Русте:

//Possible global ready flag with 3 states (true, false, None) 
let ready: Option<&mut bool> = None; 

fn main(){ 
    welcome_message(); //Displays a "Connecting..." message to the user 

    //These are special callback I created and basically when the 
    //message is received the `connected` is called. 
    //If there was an error getting the message (service is down) 
    //then `not_connected` is called. *This is working code* 
    let p = mylib::Promise::new(connected, not_connected); 

    //Call connect and start websocket send and receive threads 
    mylib::connect(p); 

    //Loop for user input 
    loop { 
     match ready { 
      Some(x) => { 
       if x == true { //If ready is true, display the prompt 
        match prompt_input() { 
         true => {}, 
         false => break, 
        } 
       } else { 
        return; //If ready is false, quit the program 
       } 
      }, 
      None => {} //Ready is None, so continue waiting 
     } 
    } 
} 

fn connected() -> &mut bool{ 
    println!("Connected to Service! Please enter a command. (hint: help)\n\n"); 
    true 
} 

fn not_connected() -> &mut bool{ 
    println!("Connection to Service failed :("); 
    false 
} 

Вопрос: Как бы вы решить эту проблему в Rust? Я попытался передать его всем вызовам методов библиотек, но затронул некоторые основные проблемы с заимствованием неизменяемого объекта в закрытии FnOnce().

+0

Хотя я бы посоветовал вам * не * использовать глобальное изменяемое состояние, я бы упущения, если бы я не делал, по крайней мере пункт [этот ответ] (http://stackoverflow.com/questions/27791532/how-do-create-a-global-mutable-singleton), который показывает, как это делается. – Shepmaster

ответ

3

Звучит так, будто вы хотите иметь два потока, которые общаются через каналы . Проверьте этот пример:

use std::thread; 
use std::sync::mpsc; 
use std::time::Duration; 

enum ConsoleEvent { 
    Connected, 
    Disconnected, 
} 

fn main() { 
    let (console_tx, console_rx) = mpsc::channel(); 

    let socket = thread::spawn(move || { 
     println!("socket: started!"); 

     // pretend we are taking time to connect 
     thread::sleep(Duration::from_millis(300)); 

     println!("socket: connected!"); 
     console_tx.send(ConsoleEvent::Connected).unwrap(); 

     // pretend we are taking time to transfer 
     thread::sleep(Duration::from_millis(300)); 

     println!("socket: disconnected!"); 
     console_tx.send(ConsoleEvent::Disconnected).unwrap(); 

     println!("socket: closed!"); 
    }); 

    let console = thread::spawn(move || { 
     println!("console: started!"); 

     for msg in console_rx.iter() { 
      match msg { 
       ConsoleEvent::Connected => println!("console: I'm connected!"), 
       ConsoleEvent::Disconnected => { 
        println!("console: I'm disconnected!"); 
        break; 
       } 
      } 
     } 
    }); 

    socket.join().expect("Unable to join socket thread"); 
    console.join().expect("Unable to join console thread"); 
} 

Здесь есть 3 темы в игре:

  1. Основного поток.
  2. Поток для чтения из «гнезда».
  3. Поток для взаимодействия с пользователем.

Каждый из этих потоков может поддерживать свои собственные не является общим состоянии. Это позволяет легче рассуждать о каждом потоке. В потоках используется channel, чтобы безопасно отправлять обновления между ними. Данные, пересекающие потоки, инкапсулируются в перечисление.

Когда я запускаю это, я получаю

socket: started! 
console: started! 
socket: connected! 
console: I'm connected! 
socket: disconnected! 
socket: closed! 
console: I'm disconnected! 
+0

Да, это имеет смысл. Большое вам спасибо (снова). Это намного более чистый и лаконичный способ сделать это. Как и все, что я читал, как правило, лучше, чем использование глобального, я просто не мог думать об этом. – SnareChops

Смежные вопросы