Skip to content

Fix deadlock in multithreaded excerpt serialisation - #34733

Open
ajuncosa wants to merge 1 commit into
musescore:mainfrom
ajuncosa:write-deadlock
Open

Fix deadlock in multithreaded excerpt serialisation#34733
ajuncosa wants to merge 1 commit into
musescore:mainfrom
ajuncosa:write-deadlock

Conversation

@ajuncosa

@ajuncosa ajuncosa commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

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 EngravingItem destructor calls Score::onElementDestruction which ends with score->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 (in QueuePool::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, whose endTransaction calls m_masterScore->update(), relaying out the master from a worker thread.

I have moved the unhide and relayout out of the writer.

@ajuncosa
ajuncosa marked this pull request as ready for review August 31, 2026 06:02
@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 78b2b6bb-a791-465e-be1b-b3e08d7423c2

📥 Commits

Reviewing files that changed from the base of the PR and between 2963eb8 and bc57855.

📒 Files selected for processing (3)
  • src/engraving/rw/mscsaver.cpp
  • src/engraving/rw/mscsaver.h
  • src/engraving/rw/write/writer.cpp
💤 Files with no reviewable changes (1)
  • src/engraving/rw/write/writer.cpp

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

writeMscz and exportPart now use UnhidePartsForWrite during serialization. The guard temporarily makes hidden parts visible, recalculates layout data, and rolls back the visibility changes through the undo stack. Writer::write no longer performs its own temporary unhide and restore sequence.

Merge Risk: 🔵 Low · up to bc578

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)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description clearly explains the deadlock, its cause, and the implementation approach. However, it omits the required issue reference and all checklist items from the repository template. Add a Resolves: #NNNNN`` issue reference, complete every checklist item, and document any applicable testing or prior attempts.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the primary change: fixing a deadlock during multithreaded excerpt serialization.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Linked repositories: Public OSS repositories can only analyze public repositories installed in this organization. No linked repositories were analyzed; skipped musescore/muse_framework.git.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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