我正在编写一个应用程序,该应用程序应该循环地从串行端口读取(例如观察程序),并且还应该向其中写入命令。
只允许主线程写入,而创建的线程只能读取。
我创建了一个简单的示例来在这里重现我的问题。 tx_thread
循环读取串行端口,并在一定条件下通过MPSC通道发送消息。 rx_thread
查找消息;当有可用的东西时,它会进行处理,并且还应该更改该结构的当前状态。
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
// this will also implement Drop trait to wait threads to
// be finished (message will be Enum instead of number in this case)
#[derive(Debug)]
struct MyStruct {
num: u32,
tx_thread: Option<thread::JoinHandle<()>>,
rx_thread: Option<thread::JoinHandle<()>>,
}
impl MyStruct {
fn new() -> MyStruct {
MyStruct {
num: 0,
tx_thread: None,
rx_thread: None,
}
}
fn start(&mut self) {
let (tx, rx) = mpsc::channel();
// tx thread will read from serial port infinitely,
// and send data to mpsc channel after certain condition
// to be processed.
let tx_thread = thread::spawn(move || {
let mut i = 0;
loop {
tx.send(i).unwrap();
i += 1;
thread::sleep(Duration::from_secs(1));
}
});
// after this will receive message, it will start
// processing and mutate `self` state if needed.
let rx_thread = thread::spawn(move || loop {
let num = rx.recv().unwrap();
println!("{:?}", num);
/* here, how do I save `num` to `self`? */
thread::sleep(Duration::from_secs(1));
});
self.tx_thread = Some(tx_thread);
self.rx_thread = Some(rx_thread);
}
}
fn main() {
let mut s = MyStruct::new();
s.start();
thread::sleep(Duration::from_secs(999999));
}
答案 0 :(得分:1)
在不和谐频道上,一个了不起的家伙(断了笔)告诉了我很多很好的解决方案,所有功劳都归功于他。
因此解决方案是将我们想要突变的属性放到Arc<Mutex<>>
中,然后将克隆的引用移到线程中。因此基本上,代码将如下所示:
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use std::time::Duration;
type MyType = Arc<Mutex<u32>>;
#[derive(Debug)]
struct MyStruct {
num: MyType,
tx_thread: Option<thread::JoinHandle<()>>,
rx_thread: Option<thread::JoinHandle<()>>,
}
impl MyStruct {
fn new() -> MyStruct {
MyStruct {
num: Arc::new(Mutex::new(0)),
tx_thread: None,
rx_thread: None,
}
}
fn start(&mut self) {
let (tx, rx) = mpsc::channel();
// tx thread will read from serial port infinitely,
// and send data to mpsc channel after certain condition
// to be processed.
let tx_thread = thread::spawn(move || {
let mut i = 0;
loop {
tx.send(i).unwrap();
i += 1;
thread::sleep(Duration::from_secs(1));
}
});
// clone here.
let arc_num = self.num.clone();
let rx_thread = thread::spawn(move || loop {
let num = rx.recv().unwrap();
// println!("{:?}", num);
// now we can use it for writing/reading.
*arc_num.lock().unwrap() = num;
println!("{:?}", *arc_num.lock().unwrap());
thread::sleep(Duration::from_secs(1));
});
self.tx_thread = Some(tx_thread);
self.rx_thread = Some(rx_thread);
}
}
fn main() {
let mut s = MyStruct::new();
s.start();
thread::sleep(Duration::from_secs(999999));
}
编辑:另一种解决方案是使用Arc<Mutex<>>
创建内部结构并在那里进行工作,从而使您可以访问所需的所有内容。
请参见下面的代码:
use std::default::Default;
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use std::time::Duration;
// this will also implement Drop trait to wait threads to
// be finished (message will be Enum instead of number in this case)
#[derive(Debug, Default)]
struct MyStructInner {
num: u32,
tx_thread: Option<thread::JoinHandle<()>>,
rx_thread: Option<thread::JoinHandle<()>>,
}
#[derive(Debug, Default)]
struct MyStruct {
inner: Arc<Mutex<MyStructInner>>,
}
impl MyStruct {
fn new() -> MyStruct {
MyStruct {
inner: Arc::new(Mutex::new(MyStructInner {
num: 0,
..Default::default()
})),
}
}
fn start(&mut self) {
let (tx, rx) = mpsc::channel();
// tx thread will read from serial port infinitely,
// and send data to mpsc channel after certain condition
// to be processed.
let tx_thread = thread::spawn(move || {
let mut i = 0;
loop {
tx.send(i).unwrap();
i += 1;
thread::sleep(Duration::from_secs(1));
}
});
// after this will receive message, it will start
// processing and mutate `self` state if needed.
let local_self = self.inner.clone();
let rx_thread = thread::spawn(move || loop {
let num = rx.recv().unwrap();
local_self.lock().unwrap().num = num;
println!("{:?}", local_self.lock().unwrap().num);
thread::sleep(Duration::from_secs(1));
});
self.inner.lock().unwrap().tx_thread = Some(tx_thread);
self.inner.lock().unwrap().rx_thread = Some(rx_thread);
}
}
fn main() {
let mut s = MyStruct::new();
s.start();
thread::sleep(Duration::from_secs(999999));
}