У меня есть поток данных, который я хочу обработать в фоновом режиме, но я хочу создать структуру или некоторые функции для управления этим потоком.
На земле C ++ я бы создал класс, который абстрагирует всеэтого прочьУ него будет метод start
, который инициализирует поток данных и запускает поток для обработки. У него был бы метод stop
, который останавливает обработку и присоединяет поток.
Однако это не совсем Rusty и даже не работает в Rust.
Пример ( Детская площадка )
use std::thread;
use std::time::Duration;
struct Handler {
worker_handle: Option<thread::JoinHandle<()>>,
stop_flag: bool, // Should be atomic, but lazy for example
}
impl Handler {
pub fn new() -> Handler {
let worker_handle = None;
let stop_flag = true;
return Handler { worker_handle, stop_flag };
}
pub fn start(&mut self) {
self.stop_flag = false;
self.worker_handle = Some(std::thread::spawn(move || {
println!("Spawned");
self.worker_fn();
}));
}
pub fn stop(&mut self) {
let handle = match self.worker_handle {
None => return,
Some(x) => x,
};
self.stop_flag = true;
handle.join();
}
fn worker_fn(&mut self) {
while !self.stop_flag {
println!("Working!");
}
}
}
fn main() {
let mut handler = Handler::new();
handler.start();
thread::sleep(Duration::from_millis(10000));
handler.stop();
}
Вывод:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:20:54
|
20 | self.worker_handle = Some(std::thread::spawn(move || {
| ______________________________________________________^
21 | | println!("Spawned");
22 | | self.worker_fn();
23 | | }));
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
--> src/main.rs:18:5
|
18 | / pub fn start(&mut self) {
19 | | self.stop_flag = false;
20 | | self.worker_handle = Some(std::thread::spawn(move || {
21 | | println!("Spawned");
22 | | self.worker_fn();
23 | | }));
24 | | }
| |_____^
= note: ...so that the types are compatible:
expected &mut Handler
found &mut Handler
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:20:54: 23:10 self:&mut Handler]` will meet its required lifetime bounds
--> src/main.rs:20:35
|
20 | self.worker_handle = Some(std::thread::spawn(move || {
| ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
Даже если я обманываю и удаляю вызов worker_fn
, я все равно не могу работать с JoinHandle
как и можно ожидать от земли C ++.
error[E0507]: cannot move out of `self.worker_handle.0` which is behind a mutable reference
--> src/main.rs:27:28
|
27 | let handle = match self.worker_handle {
| ^^^^^^^^^^^^^^^^^^ help: consider borrowing here: `&self.worker_handle`
28 | None => return,
29 | Some(x) => x,
| -
| |
| data moved here
| move occurs because `x` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
error: aborting due to previous error
Так что ясно, что я выхожу за пределы обычной модели Rust и, вероятно, не должна использовать эту стратегию.
Но я все еще хочу создать некоторый интерфейс, который позволит мне просто раскрутить поток данных, не беспокоясь об управлении потоками, и я не совсем уверен, что лучший способ сделать это.
Похоже, у меня есть две основные проблемы.
1) Как создать функцию, которая будет выполняться в потоке, который принимает данные из внешнего источника и может сигнализировать о безопасном выходе? Если бы у меня был атомный бул для его уничтожения, как бы я поделился этим между потоками?
2) Как мне справиться с присоединением потока, когда я закончу? Метод stop
должен очистить поток, но я не знаю, как отследить ссылку на него.