使用通道在线程之间传递消息。

huangapple go评论81阅读模式
英文:

Using a channel to pass message between threads

问题

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.

英文:

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()
    }
}

答案1

得分: 1

每次调用update()时,它都会创建一个新的通道。消息Flash1的通道和消息Stop的通道_不是同一个通道_。当你发送到Stop的通道时,Flash1的通道不会接收到消息,因为它们没有连接。当我们退出update()并关闭通道时,Flash1的发送部分会被丢弃,而Stop的接收部分也会被丢弃并关闭通道。

您可以将通道存储为Counter中的字段,这样它就会是同一个通道。一个可能的方式,例如,是存储Option<Sender>,在调用消息Flash1时分配给它,在调用消息Stop时发送到它。

英文:

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.

huangapple
  • 本文由 发表于 2023年7月13日 09:41:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76675387.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定