loop {
if start_button.is_high(){
thread::spawn(move || {
loop {
run_stepper_motor(
&mut menu,
&mut stepper_motor_dir, // <- Move occures here
&mut stepper_motor_step, // <- and here
&mut sensor, // <- and here
);
}
});
}
}
I'm using esp-idf-svc (with support for std), and I'm trying to make something like this above, but I don't know how can I fix this move issue. I have a few more functions in thread::spawn that say there is a move (above is only a short example). Here are some of the errors I'm getting:
(This values also don't implement clone trait)
error[E0382]: use of moved value: `stepper_motor_step`
--> src/main.rs:228:27
|
152 | let mut stepper_motor_step = PinDriver::input_output(peripherals.pins.gpio18)?;
| ---------------------- move occurs because `stepper_motor_step` has type `esp_idf_svc::hal::gpio::PinDriver<'_, Gpio18, InputOutput>`, which does not implement the `Copy` trait
...
228 | thread::spawn(move || {
| ^^^^^^^ value moved into closure here, in previous iteration of loop
...
235 | &mut stepper_motor_step,
| ------------------ use occurs due to use in closure
error[E0382]: use of moved value: `sensor`
--> src/main.rs:228:27
|
154 | let mut sensor = PinDriver::input(peripherals.pins.gpio36)?;
| ---------- move occurs because `sensor` has type `esp_idf_svc::hal::gpio::PinDriver<'_, Gpio36, esp_idf_svc::hal::gpio::Input>`, which does not implement the `Copy` trait
...
228 | thread::spawn(move || {
| ^^^^^^^ value moved into closure here, in previous iteration of loop
...
236 | &mut sensor,
| ------ use occurs due to use in closure
If you can't clone a value, you can wrap it in an Arc and pass a clone of that Arc in each iteration to the newly spawned thread. If you need mutable access to the value wrapped in the Arc, you can use an Arc<Mutex<T>> or Arc<RwLock<T>>.
The issue is not purely in the code (i.e. in the way you're using move for example), but is a more fundamental issue in the logic you're trying to express. Consider for example this situation:
the outer loop starts
start_button.is_high() is true
a thread is spawned with references to menu, stepper_motor_dir, etc etc
the if ends and the outer loop starts again
start_button.is_high() is true again
another thread is spawned, also with references to menu, stepper_motor_dir, etc etc
you now have two threads with two mutable references to the same data, this cannot happen and the compiler will prevent you from doing this!
So you just cannot express this code. You need some way to prevent the multiple references from existing. This may be done for example by not running the inner loop in a different thread and instead blocking the current thread, or by deferring the check at runtime, for example by using a Mutex (at the cost however of potential deadlock or threads getting stuck if you use them in the wrong way).
There is also another problem with your code: what if the inner thread you spawned continues running after menu, stepper_motor_dir etc etc went out of scope? You now have references to some data that doesn't exist anymore, which the compiler will also prevent. This also needs to be addressed in some way, either by waiting for the thread to finish (std::thread::scope provides a nice way to do this that the compiler can see through), or by managing menu, stepper_motor_dir etc etc's lifetime at runtime, for example with an Arc.
Ultimately however there's no "true" general solution, they all depend on the details of what you're trying to code and the trade-offs you're willing to make.
So I already was thinking about this issue (I will probably do while == value statement instead of loop, and before thread I will add if start_thread == True thought I don't know if it will work yet), but thank you for suggesting some ways of how I can do it.