a8d0cf0f by 柴进

:bug: 修复 task_queue 信号 lambda connect 跨线程 GUI 调用导致的 access violation

faulthandler 抓到 7 个 Windows access violation 栈, 全部归到同一根因:
worker_ref.finished/error/progress (QThread 信号) 和 task_completed 用
lambda connect 时, lambda 没有 QObject thread affinity, Qt 默认按
DirectConnection 处理, 导致 lambda 在 worker 线程同步执行, 链路尽头
动主线程 GUI (refresh_history / _update_summary / display_image) →
C++ 层 access violation。

Windows 表现为 fatal exception: access violation, 用户感知"crash";
macOS 触发后多被 SIGKILL 静默闪退, faulthandler 拦不到, 这就是最近
"Mac 仍闪退"剩余尾巴的同源问题。

修复: 5 处 lambda connect 全部显式 Qt.QueuedConnection, 强制 handler
进 receiver 主线程 event loop 排队, 彻底消除跨线程 GUI 调用。
1 parent 5f2a43f7
...@@ -3092,9 +3092,12 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -3092,9 +3092,12 @@ class ImageGeneratorWindow(QMainWindow):
3092 ) 3092 )
3093 3093
3094 # Connect to task completion signal 3094 # Connect to task completion signal
3095 # 🔒 QueuedConnection: lambda 没有 QObject receiver, 不强制排队的话会被当 DirectConnection,
3096 # 在发射方所在线程同步执行 → 跨线程动 GUI → access violation (Win) / 静默闪退 (Mac)
3095 self.task_manager.task_completed.connect( 3097 self.task_manager.task_completed.connect(
3096 lambda tid, img, p, refs, ar, size, model: 3098 lambda tid, img, p, refs, ar, size, model:
3097 self._on_my_task_completed(task_id, tid, img, p, refs, ar, size, model) 3099 self._on_my_task_completed(task_id, tid, img, p, refs, ar, size, model),
3100 Qt.QueuedConnection,
3098 ) 3101 )
3099 3102
3100 # Update UI 3103 # Update UI
...@@ -4681,9 +4684,11 @@ class StyleDesignerTab(QWidget): ...@@ -4681,9 +4684,11 @@ class StyleDesignerTab(QWidget):
4681 ) 4684 )
4682 4685
4683 # Connect to task completion signal 4686 # Connect to task completion signal
4687 # 🔒 QueuedConnection 同上, 防 lambda 在 worker 线程被 DirectConnection 同步触发
4684 self.parent_window.task_manager.task_completed.connect( 4688 self.parent_window.task_manager.task_completed.connect(
4685 lambda tid, img, p, refs, ar, size, mdl: 4689 lambda tid, img, p, refs, ar, size, mdl:
4686 self._on_my_task_completed(task_id, tid, img, p, refs, ar, size, mdl) 4690 self._on_my_task_completed(task_id, tid, img, p, refs, ar, size, mdl),
4691 Qt.QueuedConnection,
4687 ) 4692 )
4688 4693
4689 # Update UI 4694 # Update UI
......
...@@ -206,17 +206,24 @@ class TaskQueueManager(QObject): ...@@ -206,17 +206,24 @@ class TaskQueueManager(QObject):
206 206
207 # 绑定信号;用 worker 局部引用捕获 finish_reason,避免后续 _current_worker 被替换 207 # 绑定信号;用 worker 局部引用捕获 finish_reason,避免后续 _current_worker 被替换
208 worker_ref = self._current_worker 208 worker_ref = self._current_worker
209 # 🔒 必须 QueuedConnection: worker_ref 是 QThread, finished/error/progress 从 worker 线程发出。
210 # lambda 没有 QObject thread affinity, 默认会被当成 DirectConnection 在 worker 线程同步执行,
211 # 链路尽头会动主线程 GUI (refresh_history / _update_summary), C++ 层 access violation。
212 # Windows 表现为 fatal exception, macOS 表现为静默 SIGKILL 闪退。
209 worker_ref.finished.connect( 213 worker_ref.finished.connect(
210 lambda img_bytes, prompt, ref_imgs, ar, size, model: 214 lambda img_bytes, prompt, ref_imgs, ar, size, model:
211 self._on_task_completed(task_id, img_bytes, prompt, ref_imgs, ar, size, model, 215 self._on_task_completed(task_id, img_bytes, prompt, ref_imgs, ar, size, model,
212 getattr(worker_ref, 'finish_reason', None)) 216 getattr(worker_ref, 'finish_reason', None)),
217 Qt.QueuedConnection,
213 ) 218 )
214 worker_ref.error.connect( 219 worker_ref.error.connect(
215 lambda error: self._on_task_failed(task_id, error, 220 lambda error: self._on_task_failed(task_id, error,
216 getattr(worker_ref, 'finish_reason', None)) 221 getattr(worker_ref, 'finish_reason', None)),
222 Qt.QueuedConnection,
217 ) 223 )
218 worker_ref.progress.connect( 224 worker_ref.progress.connect(
219 lambda status: self.task_progress.emit(task_id, 0.5, status) 225 lambda status: self.task_progress.emit(task_id, 0.5, status),
226 Qt.QueuedConnection,
220 ) 227 )
221 228
222 self.task_started.emit(task_id) 229 self.task_started.emit(task_id)
......