Reputation: 19
I need to terminate a loop in a thread in Rust by using (tx, rx) channel in Rust to pass a message to the loop that's running. I have carefully followed chapters 15 -17 of the online rust book to implement a (tx, rx) channel in Rust to terminate a continuously running loop in a thread, but the message won't get through! I am using ICED for the Gui I'm designing and have modified an online ICED example, and it compiles.
use chrono::Utc;
use iced::pure::widget::{Button, Column, Container, Text};
use iced::pure::Sandbox;
use iced::Settings;
use rust_gpiozero::*;
use std::thread;
use std::thread::sleep;
//use std::io::{self, BufRead};
use std::env;
use std::io;
use std::io::BufRead;
use std::process;
use std::sync::mpsc;
use std::time::Duration;
//fn main() -> Result<(), iced::Error> {
//Counter::run(Settings::default())
//}
fn main() -> Result<(), iced::Error> {
Counter::run(Settings::default())
}
struct Counter {
count: i32,
}
#[derive(Debug, Clone, Copy)]
enum CounterMessage {
Increment,
Decrement,
Increment2,
Decrement2,
Flash1,
Stop,
}
impl Sandbox for Counter {
type Message = CounterMessage;
fn new() -> Self {
Counter { count: 0 }
}
fn title(&self) -> String {
String::from("Counter app")
}
fn update(&mut self, message: Self::Message) {
let (tx, rx) = mpsc::channel();
//let _val = String::from("hi");
match message {
CounterMessage::Increment => self.count += 1,
CounterMessage::Decrement => self.count -= 1,
CounterMessage::Increment2 => self.count += 2,
CounterMessage::Decrement2 => self.count -= 2,
CounterMessage::Flash1 => {
thread::spawn(move || loop {
let led = LED::new(17);
led.on();
sleep(Duration::from_millis(500));
led.off();
sleep(Duration::from_millis(500));
//let r1 = rx.recv().unwrap();
//let r1 = rx.recv();
match rx.recv() {
Ok(_) => {
break;
}
Err(_) => {
println!("error!")
}
}
continue;
//}
});
}
CounterMessage::Stop => {
thread::spawn(move || {
let _val = String::from("hi");
tx.send(_val);
});
}
}
}
fn view(&self) -> iced::pure::Element<Self::Message> {
let label = Text::new(format!("Count: {}", self.count));
let incr = Button::new("Increment").on_press(CounterMessage::Increment);
let decr = Button::new("Decrement").on_press(CounterMessage::Decrement);
let incr2 = Button::new("Increment+2").on_press(CounterMessage::Increment2);
let decr2 = Button::new("Decrement-2").on_press(CounterMessage::Decrement2);
let flash1 = Button::new("FLASH1").on_press(CounterMessage::Flash1);
let stop = Button::new("STOP FLASH!").on_press(CounterMessage::Stop);
let col = Column::new()
.push(incr)
.push(label)
.push(decr)
.push(incr2)
.push(decr2)
.push(flash1)
.push(stop);
Container::new(col)
.center_x()
.center_y()
.width(iced::Length::Fill)
.height(iced::Length::Fill)
.into()
}
}
Upvotes: 0
Views: 430
Reputation: 71430
Every time update()
is called, it creates a new channel. The channels of the message Flash1
and of the message Stop
are just not the same channel. When you send into the channel of Stop
, the channel of Flash1
won't receive the message, because they're not connected. The sender part of Flash1
is dropped when we exit update()
and the channel is closed, and the receiver part of Stop
is also dropped and the channel is closed.
You can store the channel as a field in Counter
, so it will be the same channel. One possibility, for example, is to store Option<Sender>
, assign to it when the message Flash1
is called, and send into it when the message Stop
is called.
Upvotes: 1