My goal is to have a background thread counting up every second, which can be started and stopped by buttons on the UI. The gui should display the current time. I thought that the communication between the gui and the background thread could be done via channels for the commands, and via a mutex for the number being counted upwards. In this example, I have omitted the communication via channels, and just focus on the mutex.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
use eframe::egui;
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let options = eframe::NativeOptions {
initial_window_size: Some(egui::vec2(320.0, 240.0)),
fullscreen: false,
default_theme: eframe::Theme::Light,
..Default::default()
};
eframe::run_native(
"My egui App",
options,
Box::new(|_cc| Box::new(Timer::default())),
);
}
struct Timer {
time: u32,
counter: Arc<Mutex<i32>>,
}
impl Default for Timer {
fn default() -> Self {
let counter = Arc::new(Mutex::new(0));
let counter_clone = Arc::clone(&counter);
//spawn looping thread
let _ = thread::spawn(move || {
loop {
let mut num = counter_clone.lock().unwrap();
*num += 1;
std::thread::sleep_ms(100);
}
});
Self {
time: 0,
counter: counter,
}
}
}
impl eframe::App for Timer {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
let mut num = self.counter.lock().unwrap();
ui.heading(format!("My egui Application {}", num));
});
}
}
This compiles and runs, but it is super laggy. Could you help me to understand what I can do better?
In your sleeping loop you hold the lock for the whole duration you're sleeping.
loop {
let mut num = counter_clone.lock().unwrap();
*num += 1;
std::thread::sleep_ms(100);
} // counter_clone only gets released here.
You either want to add a manual call to drop
after you increase the number:
loop {
let mut num = counter_clone.lock().unwrap();
*num += 1;
drop(num); // counter_clone now gets released here before we wait.
std::thread::sleep_ms(100);
}
Or just lock
it in place:
loop {
*counter_clone().lock.unwrap() += 1; // counter_clone gets unlocked at the end of this statement.
std::thread::sleep_ms(100);
}