Skip to content

Make cross-thread audio params and channel/server flags std::atomic#3802

Open
mcfnord wants to merge 1 commit into
jamulussoftware:mainfrom
mcfnord:atomic-flags-3798-cde
Open

Make cross-thread audio params and channel/server flags std::atomic#3802
mcfnord wants to merge 1 commit into
jamulussoftware:mainfrom
mcfnord:atomic-flags-3798-cde

Conversation

@mcfnord

@mcfnord mcfnord commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Second slice of the audit in #3798, following the same experimental approach as #3800: only the mechanical conversions from batches C (GUI-thread parameters read by the audio callback), D (client-side channel state), and E (the server disconnect flag). Everything that needs an actual design decision is deliberately left out — see "Not included" below.

What changes

Nine members become std::atomic, keeping plain operator syntax at every call site (same rationale as #3800: per #3786, the overloaded operators are the simplest form, and default sequentially-consistent operations are negligible at these rates). No control flow changes at all this time — every access stays a plain load or store through the operators.

Member Written by Read by
CClient::bMuteOutStream main thread (setter) sound thread, every frame
CClient::fMuteOutStreamGain main thread (SetRemoteChanGain, under MutexGainOrPan) sound thread, no lock
CClient::iAudioInFader main thread (setter) sound thread, every frame
CClient::bReverbOnLeftChan main thread (setter) sound thread, every frame
CClient::iReverbLevel main thread (setter) sound thread, every frame
CClient::iInputBoost main thread (setter) sound thread, every frame
CChannel::bIsEnabled main thread (under Mutex) socket thread in PutAudioData(), no lock
CChannel::iConTimeOut main thread (Disconnect(), no lock) socket/audio threads (under MutexSocketBuf), IsConnected() readers
CServer::bChannelIsNowDisconnected thread-pool workers main thread after future.wait()

fMuteOutStreamGain is an addendum to the batch-C table in #3798, found while preparing this patch: it is written by the GUI thread under MutexGainOrPan but read lock-free by the sound thread in ProcessAudioDataIntern() — a writer-side-only mutex synchronizes nothing, and the int members in the same table can additionally tear. It is the same mechanical pattern, so it is included here.

The one comment change: the note above the bChannelIsNowDisconnected store (server.cpp) claimed "no mutex is needed … an atomic write". As discussed in #3786, a plain bool store is not an atomic write in the C++ memory model. With the member now std::atomic<bool>, the comment is reworded to be true.

Not included (needs discussion, not mechanics)

  • C: SetReverbOnLeftChan() also calls AudioReverb.Clear() on the GUI thread while the sound thread may be inside AudioReverb.Process() — concurrent mutation of filter state. The clean fix (deferring the clear onto the audio thread) changes behavior slightly and deserves its own review.
  • D3: iNetwFrameSize/iNetwFrameSizeFact are written under Mutex but read under MutexSocketBuf; fixing that is a locking-design choice.
  • F: the Close() fd overwrite race is the intended unblock mechanism and needs a considered design if it is to change at all.

Behavior

No intended behavior change. The iConTimeOut -= n in PutAudioData() becomes an atomic fetch_sub, but that path already runs under MutexSocketBuf, so ordering there is unchanged; the fix is for the lock-free writers/readers elsewhere.

Tested

  • Full Linux client+server build (Qt 5.15, JACK enabled): compiles with no new warnings; clang-format-14 clean.
  • Headless server smoke test: starts, runs, exits cleanly on SIGTERM (OnHandledSignal: 15).

Note for whoever merges: #3800 also adds #include <atomic> to src/client.h, so whichever of the two lands second will need a trivial rebase of that one line.

🤖 Generated with Claude Code

Second slice of jamulussoftware#3798 (batches C, D, E — mechanical conversions only):
GUI-thread parameters read by the audio callback, client channel state
read by the socket thread, and the server disconnect flag written by
thread-pool workers. The comment at the disconnect flag claimed the
write was atomic; it now is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ann0see

ann0see commented Jul 18, 2026

Copy link
Copy Markdown
Member

The one comment change: the note above the bChannelIsNowDisconnected store (server.cpp) claimed "no mutex is needed … an atomic write".

This is likely the comment I read a while ago which made me suspicious.

@pljones

pljones commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

GUI-thread parameters read by the audio callback

I mean, this is fundamentally broken... What does it do if there isn't a GUI? State shouldn't in the GUI. I'd rather the right fix was put in: use signals to pass state out of the GUI (not hold anything but the visual representation), respond to signals of change in state from the Client.

Or does this just mean "on the main thread"?

@mcfnord
mcfnord marked this pull request as ready for review July 18, 2026 18:27
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.

3 participants