Skip to content

Make bRun atomic#3786

Draft
ann0see wants to merge 1 commit into
mainfrom
ai-findings-autofix/src-socket.h
Draft

Make bRun atomic#3786
ann0see wants to merge 1 commit into
mainfrom
ai-findings-autofix/src-socket.h

Conversation

@ann0see

@ann0see ann0see commented Jul 15, 2026

Copy link
Copy Markdown
Member

This PR applies 1/1 suggestions from code quality AI findings.

It's very likely that we have various places where we have bugs due to assuming bools are atomic while they are not.

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
@ann0see ann0see changed the title Potential fix for 1 code quality finding a+ Jul 15, 2026
@ann0see ann0see changed the title a+ Make bRun atomic Jul 15, 2026
@ann0see

ann0see commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

CC: @softins - I'll need to try it locally but I'm fairly confident that we have a project wise misunderstanding about variables being thread safe while they are not.

@softins

softins commented Jul 15, 2026

Copy link
Copy Markdown
Member

This doesn't look at all necessary to me. It's not like a counter being incremented, or some other read-modify-write operation. bRun is initialised to true, and then the loop just keeps running until it becomes false. Setting it to false is a single write, which by definition is atomic. I don't see any thread safety issue here at all.

@mcfnord

mcfnord commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

https://stackoverflow.com/questions/16320838/when-do-i-really-need-to-use-atomicbool-instead-of-bool

It looks like each thread has its own bool that it reads and modifies. If so, I agree there's no risk of cached write by another thread here.

@ann0see

ann0see commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

Setting it to false is a single write, which by definition is atomic.

I am unsure if that's really the case. I remember that on x86 there are combinations that this doesn't hold: write to L1 of core A but core B still has the old value in its L1 cache. B may not get updated. This could yield to infinite looping.

Citing the stackoverflow post:

Without atomic there is no guarantee that you'll ever see the update in the other thread at all, or that you'll see updates to variables in the same order that you make them in a different thread.

Assuming the bool is really thread local it's fine - however it still stands that in the codebase we do have other areas where this is probably not true. I remember seeing a comment about the write being atomic on a bool where I questioned if this is really the case.

@softins

softins commented Jul 16, 2026

Copy link
Copy Markdown
Member

Setting it to false is a single write, which by definition is atomic.

I am unsure if that's really the case. I remember that on x86 there are combinations that this doesn't hold: write to L1 of core A but core B still has the old value in its L1 cache. B may not get updated. This could yield to infinite looping.

Hmm, if that's really the case, I'd class that as a hardware bug! A write to a memory location ought to invalidate any cached copies of it. Unless there are subtleties that I have yet to understand, which is quite possible!

Citing the stackoverflow post:

Without atomic there is no guarantee that you'll ever see the update in the other thread at all, or that you'll see updates to variables in the same order that you make them in a different thread.

OK, so my next question to understand this would be: what, at the code level, does atomic do that overcomes this, that a standard write does not?

Assuming the bool is really thread local it's fine - however it still stands that in the codebase we do have other areas where this is probably not true. I remember seeing a comment about the write being atomic on a bool where I questioned if this is really the case.

@ann0see

ann0see commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

what, at the code level, does atomic do that overcomes this, that a standard write does not?

I believe it's a memory fence.

@pljones

pljones commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

what, at the code level, does atomic do that overcomes this, that a standard write does not?

I believe it's a memory fence.

So there's a "memory fence" code operation?

@ann0see

ann0see commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@ann0see

ann0see commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

I suspect the hang's root cause is stuff like this.

@softins

softins commented Jul 16, 2026

Copy link
Copy Markdown
Member

Ok, I'm learning things about this that I didn't know before.

In this particular case, the loop testing bRun is in the separate high-priority thread that reads the inbound data from the socket(s). But the Stop() method that sets bRun to terminate the loop is likely called in the main application event thread.

So that suggests std::atomic<bool> would indeed be needed, which is new knowledge to me.

I do wonder if the explicit load and store methods are actually required? Are there not operator overloads within std::atomic to allow normal read and write syntax?

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.

4 participants