Fix deadlock in multithreaded excerpt serialisation - #34733
Conversation
…ed excerpt serialisation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
💤 Files with no reviewable changes (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthrough
Merge Risk: 🔵 Low · up to The change moves temporary visibility and layout work before parallel serialization, but overlapping saves or active score transactions could leave unrelated score changes rolled back or temporarily inconsistent. The PR is mergeable with explicit owner awareness and follow-up to ensure rollback is limited to transactions opened by serialization. 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Linked repositories: Public OSS repositories can only analyze public repositories installed in this organization. No linked repositories were analyzed; skipped Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The goal is to avoid side effects on the score during write/serialisation, so excerpt serialisation can safely run in separate threads.
There was a deadlock when saving scores (with "Save as...") that contained multi measure rests and some hidden parts. The save called layout in that case, which frees Systems/Pages, and the
EngravingItemdestructor callsScore::onElementDestructionwhich ends withscore->elementDestroyed().send(e). This send was cross-thread, and that channel has a main-thread receiver for every score, so the send must register a port on the main thread's slot (QueuePool::regPort), and this locks the same mutex that the main thread is holding while it's processing queued callbacks (inQueuePool::processMessages), and the save itself is one of the queued commands.Apart from the freezing
doLayout()call, the write was also modifying the score in other ways (start/endCmd(),undoChangeProperty(VISIBLE, true)), and all this routes to the master score's single shared TransactionManager, whoseendTransactioncallsm_masterScore->update(), relaying out the master from a worker thread.I have moved the unhide and relayout out of the writer.