2017-12-21 9 views
1

Ich versuche, eine einfache Bibliothek zu schreiben, die einen Hintergrund-Worker-Thread hat, der Befehle verarbeitet, wenn die Bibliotheksfunktionen aufgerufen werden.Hintergrund-Arbeitsthread und Synchronisierung in Rust

Die Art, wie ich es normalerweise in C tun würde, ist ein globales Semaphor-Handle, das der Arbeiter blockieren würde. Die Funktionen würden den Semaphor geben, nachdem sie einen Befehl gesendet haben, an welchem ​​Punkt der Arbeiter die Blockierung aufheben würde ... Es gibt andere Wege, aber dies ist nur ein Beispiel.

Ich habe ein paar Fragen dazu, wie ich mit Rust etwas Ähnliches erreichen kann.

  1. Wie verhindere ich, dass ein Thread schließt, sobald die Funktion, die ihn erstellt hat, zurückkehrt? Zum Beispiel würde der Thread erstellt werden, wenn ich init() aufrufen, aber würde verlassen, wenn init() zurückgibt, wie dies zu verhindern?

  2. Wie haben Sie eine globale Synchronisationsmethode zwischen den Worker-Thread- und Funktionsaufrufen? Ich schaute auf die Verwendung von Kanälen, aber wie greife ich auf die rx aus dem Thread und mehrere tx aus verschiedenen Funktionen? send_cmd_a() zB send_cmd_b() auf dem gleichen Thread

Pseudo-Code, was ich versuche erreichen zu:

static (tx, rx) = mpsc::channel(); //how to do something like this? 

fn init() { 
    thread::spawn(|| { 
     loop { 
      let cmd = rx.recv().unwrap(); //blocks till there is data 
              //process data.... 
      if cmd == "exit" { 
       return; 
      } 
     } 
    }); 
} 

fn send_cmd_a() { 
    //Do a bunch of other stuff... 
    tx.send("cmd_a").unwrap(); 
} 

fn exit() { 
    tx.send("exit").unwrap(); 
} 

Muss ich ein großes Objekt erstellen, die alle diese verkapselt, damit der Besitz Synchronisationsmechanismus? (antwortet immer noch nicht auf Frage # 1)

Was wäre die bevorzugte Art, so etwas in Rust zu machen?

+0

[Wie erstelle ich ein globales, veränderliches Singleton?] (Https://stackoverflow.com/q/27791532/155423). – Shepmaster

+0

* Wie verhindere ich das Schließen eines Threads, sobald die Funktion, die ihn erzeugt hat, zurückkehrt * - das ist schon das Verhalten von 'thread :: spawn'. – Shepmaster

+0

@Shempmaster Sie haben Recht. Ich habe mich geirrt, es scheint, dass die Threads offen bleiben, aber beim Programm-Exit automatisch geschlossen wurden. Danke auch für den Link – Marius

Antwort

1

Ich denke, ich habe einen Weg gefunden, um zu implementieren, was ich in Rust wollte, ohne globale Variablen zu verwenden.

struct Device { 
    sender: Sender<u8>, //other stuff 
} 

trait New { 
    fn new() -> Self; 
} 

trait SendCommand { 
    fn send_command(&self, u8); 
} 

impl New for Device { 
    fn new() -> Device { 
     let (tx, rx) = channel(); 
     let device = Device { sender: tx }; 
     thread::spawn(move || { 
      loop { 
       let cmd = rx.recv().unwrap(); 
       println!("Command: {}", cmd); //process commands here 
      } 
     }); 
     return device; 
    } 
} 

impl SendCommand for Device { 
    fn send_command(&self, cmd: u8) { 
     self.sender.send(cmd).unwrap(); 
    } 
} 

fn main() { 
    let dev = Device::new(); //create the device 
    for i in 0..10 { 
     dev.send_command(i); //send commands 
     sleep(Duration::from_millis(50)); 
    } 
    loop {} 
}