Skip to content

fix: Race condition in the NapariLiveWidget for the new alignment feature - #461

Merged
hongquanli merged 1 commit into
masterfrom
fix/napari-widget-illumination-race
Jan 18, 2026
Merged

fix: Race condition in the NapariLiveWidget for the new alignment feature#461
hongquanli merged 1 commit into
masterfrom
fix/napari-widget-illumination-race

Conversation

@hongquanli

@hongquanli hongquanli commented Jan 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes race condition where NapariLiveWidget sends duplicate MCU illumination commands during acquisition mode switches, causing command timeouts

Problem

During multi-point acquisition, when the worker thread switches microscope modes, a race condition occurs:

  1. Worker emits signal_current_configuration(config) (Qt signal to GUI)
  2. Worker calls set_microscope_mode(config) → sends SET_ILLUMINATION cmd
  3. Worker calls turn_on_illumination() → sends TURN_ON_ILLUMINATION cmd (e.g., cmd 32)
  4. GUI thread (delayed) processes signal → napariLiveWidget.update_ui_for_mode(config)
  5. GUI updates slider → triggers valueChangedupdate_config_illumination_intensity()
  6. BUG: GUI calls update_illumination() → sends duplicate SET_ILLUMINATION cmd (e.g., cmd 33)

With two commands sent nearly simultaneously:

  • _cmd_id becomes 33 (the last one assigned)
  • MCU sends ACKs for cmd 32, but system expects cmd 33
  • Cmd 33's ACK is never matched → timeout after 3.5 seconds

From the log:

18:10:50.645 - Worker: >>> sending command 32, type=TURN_ON_ILLUMINATION
18:10:50.645 - GUI:    >>> sending command 33, type=SET_ILLUMINATION  ← DUPLICATE!
18:10:50.649 - [MCU] !!! received ack for command 32, but waiting for command 33
... (repeated for 3.5 seconds) ...
18:10:54.182 - [MCU] !!! Command 33 ABORTED: Command timed out

Solution

LiveControlWidget already has an is_switching_mode guard to prevent this. NapariLiveWidget was missing it.

Added the same guard pattern to NapariLiveWidget:

  • Added is_switching_mode flag to constructor
  • Wrapped update_ui_for_mode() with try/finally to set/clear the flag
  • Added early return in update_config_illumination_intensity(), update_config_exposure_time(), and update_config_analog_gain() when flag is set

🤖 Generated with Claude Code

@hongquanli hongquanli changed the title Fix race condition causing MCU command timeouts during acquisition Fix race condition in the NapariLiveWidget Jan 18, 2026
@hongquanli hongquanli changed the title Fix race condition in the NapariLiveWidget fix: Race condition in the NapariLiveWidget for the new alignment feature Jan 18, 2026
NapariLiveWidget was missing the is_switching_mode guard that
LiveControlWidget has. During acquisition mode switches, this caused
duplicate set_illumination() calls from two threads:

1. Worker thread calls set_microscope_mode() → update_illumination()
2. GUI thread receives signal → update_ui_for_mode() → slider.setValue()
   → valueChanged → update_config_illumination_intensity() →
   update_illumination() (DUPLICATE)

Added is_switching_mode guard to NapariLiveWidget to prevent the
duplicate MCU commands during mode switches.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hongquanli
hongquanli force-pushed the fix/napari-widget-illumination-race branch from 6ee6a3e to 49e0025 Compare January 18, 2026 23:29
@hongquanli
hongquanli merged commit 5f4b158 into master Jan 18, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant