fix thread locking when reading temeprature

This commit is contained in:
2026-07-11 22:18:08 +02:00
parent 5338304ee8
commit d6da2f2bda
3 changed files with 63 additions and 17 deletions
+7 -13
View File
@@ -33,23 +33,17 @@ class TemperatureResult(Resultable, Drawable):
self.ylabel = "Temperature (C)" self.ylabel = "Temperature (C)"
# Initialize data lists # Initialize data lists
self.x = [] if x is None else x
self.y = [] if y is None else y
self.setpoint = [] if setpoint is None else setpoint self.setpoint = [] if setpoint is None else setpoint
if (x is None) and (y is None) and (desc is None) and (job_id is None) and (job_date is None): # Set metadata if provided
# Empty initialization - will be filled later if desc is not None:
self.x = []
self.y = []
elif (x is not None) and (y is not None) and (desc is not None) and (job_id is not None) and (job_date is not None):
# Full initialization
self.x = x
self.y = y
self.description = desc self.description = desc
if job_id is not None:
self.job_id = job_id self.job_id = job_id
if job_date is not None:
self.job_date = job_date self.job_date = job_date
else:
raise ValueError("Wrong usage of __init__!")
def get_number_of_channels(self): def get_number_of_channels(self):
"""Returns 1 for temperature data.""" """Returns 1 for temperature data."""
+6
View File
@@ -998,8 +998,14 @@ class DamarisGUI:
""" """
# Check if temperature monitoring is enabled # Check if temperature monitoring is enabled
if not config.get("enable_temperature_monitoring", False): if not config.get("enable_temperature_monitoring", False):
# Stop any existing monitor if temperature monitoring is disabled
self.stop_temperature_monitoring()
return return
# Stop any existing monitor before starting a new one
if self.temp_monitor is not None:
self.stop_temperature_monitoring()
controller_type = config.get("temperature_controller_type", "eurotherm") controller_type = config.get("temperature_controller_type", "eurotherm")
temp_interval = config.get("temperature_interval", 2.0) temp_interval = config.get("temperature_interval", 2.0)
+50 -4
View File
@@ -10,6 +10,14 @@ import threading
import time import time
import datetime import datetime
try:
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk as gdk
HAS_GTK = True
except (ImportError, ValueError):
HAS_GTK = False
from damaris.data import TemperatureResult from damaris.data import TemperatureResult
from damaris.tools.temperature import TemperatureController from damaris.tools.temperature import TemperatureController
@@ -89,10 +97,42 @@ class TemperatureMonitor(threading.Thread):
self.result.job_date = datetime.datetime.now() self.result.job_date = datetime.datetime.now()
self.result.job_id = id(self) self.result.job_id = id(self)
# Optional: store in data_pool # Optional: store in data_pool (thread-safe for GTK)
if self.data_pool is not None: if self.data_pool is not None:
# Make a deep copy of the result to avoid thread issues
with self._lock: with self._lock:
self.data_pool[self.data_key] = self.result # Copy the data lists
x_copy = self.result.x[:] if hasattr(self.result, 'x') and self.result.x else []
y_copy = self.result.y[:] if hasattr(self.result, 'y') and self.result.y else []
setpoint_copy = self.result.setpoint[:] if hasattr(self.result, 'setpoint') and self.result.setpoint else []
job_id_copy = getattr(self.result, 'job_id', None)
job_date_copy = getattr(self.result, 'job_date', None)
desc_copy = getattr(self.result, 'description', {}).copy() if hasattr(self.result, 'description') and isinstance(getattr(self.result, 'description', None), dict) else {}
xlabel_copy = getattr(self.result, 'xlabel', "Time (s)")
ylabel_copy = getattr(self.result, 'ylabel', "Temperature (C)")
# Create copy outside the lock to minimize lock time
result_copy = TemperatureResult(
x=x_copy,
y=y_copy,
setpoint=setpoint_copy,
desc=desc_copy,
job_id=job_id_copy,
job_date=job_date_copy
)
result_copy.xlabel = xlabel_copy
result_copy.ylabel = ylabel_copy
# Update data_pool in GTK thread if GTK is available
if HAS_GTK:
# Use gdk.threads_enter/leave for thread-safe GTK access
gdk.threads_enter()
try:
self.data_pool[self.data_key] = result_copy
finally:
gdk.threads_leave()
else:
self.data_pool[self.data_key] = result_copy
except Exception as e: except Exception as e:
print(f"TemperatureMonitor error: {e}") print(f"TemperatureMonitor error: {e}")
@@ -112,8 +152,14 @@ class TemperatureMonitor(threading.Thread):
""" """
self._running = False self._running = False
self.quit_flag.set() self.quit_flag.set()
# Wait for the thread to finish its current iteration # Wait for the thread to finish, with a generous timeout
self.join(timeout=self.interval + 0.5) # Use a longer timeout to account for potential delays
if self.is_alive():
self.join(timeout=5.0) # Wait up to 5 seconds
if self.is_alive():
print("Warning: TemperatureMonitor thread did not stop gracefully")
# Thread is still running, but we can't force stop it
# The next start will check if it's alive and handle it
def reset(self): def reset(self):
""" """