-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modifying a shared variable from an async interrupt #158
Comments
When your function ( You can do this in a lot of ways (some better and some worse), note that this is quite complex to do and understand in Rust, reading about threads and how to share data across them will make things a lot clearer! An easy way to do this is by using the OnceCell library. use std::sync::{Arc, Mutex, OnceLock};
use std::thread;
// define our global data, not containing anything at the moment
static GLOBAL_DATA: OnceLock<Arc<Mutex<i32>>> = OnceLock::new();
/*
Or you can use
static GLOBAL_DATA: LazyCell<Arc<Mutex<i32>>> = LazyCell::new(|| {
println!("initializing");
Arc::new(Mutex::new(92))
});
*/
fn main() {
// Initialize our global data
GLOBAL_DATA.set(Arc::new(Mutex::new(0))).unwrap();
// Note the .unwrap() here, if a value has been set before you cannot set it again with this
// This stores our threads handles
let mut handles = vec![];
// Lets make some threads
for i in 0..5 {
// the .unwrap() here will panic if you haven't set a value to the global instance
let global_data = GLOBAL_DATA.get().unwrap();
let handle = thread::spawn(move || {
let mut num = global_data.lock().unwrap();
*num += i;
println!("Thread {i} set value to: {num}");
});
handles.push(handle);
}
// Wait for them to finish...
for handle in handles {
handle.join().unwrap();
}
let num = GLOBAL_DATA.get().unwrap().lock().unwrap();
println!("Final value of global data: {num}");
} Another solution would be to pass an instance of your data in your function (you mentioned that you want to pass more variables to this function, this is also an example on how to do it): use std::error::Error;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use rppal::gpio::{Gpio, Event, Trigger};
const INPUT_PIN_GPIO: u8 = 27;
fn input_callback(event: Event, my_data: Arc<Mutex<i32>>) {
println!("Input event: {:?}", event);
*my_data.lock().unwrap() = 10;
}
fn main() -> Result<(), Box<dyn Error>> {
// initialize our data
let my_data = Arc::new(Mutex::new(0));
// we need this because set_async_interrupt will move it
let my_data_instance = my_data.clone();
// configure input pin
let mut input_pin = Gpio::new()?.get(INPUT_PIN_GPIO)?.into_input_pullup();
input_pin.set_async_interrupt(
Trigger::FallingEdge,
Some(Duration::from_millis(50)),
move |event| {
// Note: you can add more parameters here now!
input_callback(event, my_data_instance.clone());
},
)?;
// and here, some later on in your program, can check your value
println!("{}", my_data.lock().unwrap());
Ok(())
} |
Thank you so much for your great answer! Maybe this example could be added to the |
@golemparts do you think it's worth to have an example that's similar to my second snippet? I'm up to make the PR. |
That would definitely be helpful, as these kinds of questions come up relatively often. If you can tweak it to be more inline with the style of the current examples I'd be happy to accept a PR. |
Hi,
I'm working on a project with a StateMachine (using statig library), and I would like to send events to this StateMachine on InputPin events.
I'm configuring my input like this:
How would be the best way to achieve this?
I'm not very experimented in Rust and instinctively I thought of some sort of global variable and a Mutex, but I can't figure out how to make it work and I'm not sure if I'm going in the right direction.
Thanks for your help and your work on this library!
NOTE: I simplified the use case for the example, but I have more than one Input that can send different events to the StateMachine
The text was updated successfully, but these errors were encountered: