I'm making a Python module, written in Rust, using pyo3, that will:
- Run its own thread
- Read an input pin on a Raspberry Pi, counting how many times the state changes
- Let Python query the counter
So far, my code looks like this:
use std::thread;
use pyo3::prelude::*;
#[pyclass]
struct CountWatcher {
// The number of the GPIO pin we'll be watching
// Can't be read from Python
pin: u8,
// How many times the pin changed state
// Can be read from Python
#[pyo3(get)]
count: u128,
// Thread handle
t: thread::JoinHandle<()>,
}
#[pymethods]
impl CountWatcher {
#[new]
fn new(pin: u8) -> Self {
let t = thread::spawn(|| {
loop {
// This is where the code that reads the GPIO pin, and increments count will eventually go
println!("Test");
std::thread::sleep(std::time::Duration::from_secs(1));
}
});
Self {
pin,
count: 0,
t: t,
}
}
}
#[pymodule]
fn countwatcher(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<CountWatcher>()?;
Ok(())
}
This code works, but the problem I'm having is somehow getting a reference to the instance inside the thread so I can update count
, while still letting Python check count
anytime it wants.
I thought something like this would work, but it doesn't:
fn new(pin: u8) -> Arc<Self> {
let mut inst = Self {
pin,
count: 0,
t: None,
};
let mut inst_1 = Arc::new(inst);
let mut inst_2 = inst_1.clone();
let t = thread::spawn(move || {
loop {
inst_1.count += 1;
std::thread::sleep(std::time::Duration::from_secs(1));
}
});
inst_2.t = Some(t);
inst_2
}
Note that I had to convert the struct's t
type to Option<thread::JoinHandle()>>
, since here, I need to create the instance before creating the thread. Also, my new
method is now returning an Arc<Self>
instead of just Self
, which I'm not entirely sure I'm allowed to do.
I also tried using Arc<Mutex<CountWatcher>>
, but then I need to either return an Arc<Mutex<CountWatcher>>
from new, or return inst_2.lock()
, which would just permanently lock it.