• std::atomic work as volatile, or not, I think not...

    From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Sun May 10 21:51:00 2026
    From Newsgroup: comp.lang.c++

    Well, how much god damn optimization is a 100% conforming compiler
    allowed to do on my std::atomics?

    Can they be used as if they are "volatile", or not, damn seems not...?
    If I make three atomic stores, I better get those three atomic stores in
    my generated ASM or something, damn it!

    But, I am not 100% sure this is guaranteed unless another thread is in
    there. I know every std::atomic impl I have seen is laced with volatile somewhere. But, is it required to be? Or, well, shit.

    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.

    Look at the following code:

    Is volatile ct_atomic_word aword = { 0 }; even legal? _______________________________
    #include <iostream>
    #include <cstdint>
    #include <atomic>

    // humm... For certian use cases,
    // volatile might be needed here, say
    // for embeded work, controlling something,
    // ect...

    // or is std::atomic guaranteed to work

    typedef std::uint32_t ct_word;
    typedef std::atomic<ct_word> ct_atomic_word;


    int main()
    {
    ct_atomic_word aword = { 0 };

    // na... but, well, for tricky hardware work?
    // oh yeah. sucks. need that volatile.

    // is this even okay? Used with a std::atomic?
    //volatile ct_atomic_word aword = { 0 };

    {
    aword.store(1, std::memory_order_relaxed);
    aword.store(2, std::memory_order_relaxed);
    aword.store(3, std::memory_order_relaxed);
    }

    std::cout << "aword = " << aword.load(std::memory_order_relaxed) << std::endl;

    return 0;
    }
    _______________________________

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Mon May 11 08:25:55 2026
    From Newsgroup: comp.lang.c++

    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, how much god damn optimization is a 100% conforming compiler
    allowed to do on my std::atomics?

    Can they be used as if they are "volatile", or not, damn seems not...?
    If I make three atomic stores, I better get those three atomic stores in
    my generated ASM or something, damn it!

    But, I am not 100% sure this is guaranteed unless another thread is in there. I know every std::atomic impl I have seen is laced with volatile somewhere. But, is it required to be? Or, well, shit.

    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning below is incorrect - I am not an expert here by any means.

    As far as I know, there is no requirement for atomic accesses to act
    like volatile accesses - they are not directly observable behaviour. Of course, if there are multiple threads (and the compiler will normally
    have to assume that there are), it would normally be extremely difficult
    for the compiler to determine that a given atomic access does not have
    some effect on the results of other observable behaviour - hence it will generate code for the access.

    However, here you have used "memory_order_relaxed". Your code thus says nothing about orders. All that your code says is that "aword" can be
    read as 0, 1, 2 or 3 by other threads - and that in the current thread,
    the final read will definitely be 3. In fact, I think the compiler can
    assume that since "aword" is local and does not escape from main(),
    there is no non-UB way for another thread to see it at all - it can
    probably be eliminated entirely from the code. At most, a single store
    is sufficient.

    When testing this kind of thing, I recommend that you do not use
    <iostream> or any other kind of output, or even "main()". Use
    godbolt.org, and look at the generated assembly. IO calls will dominate
    the generated code and make it very difficult to see what is actually
    going on. Instead, declare "extern int get_int(); extern void
    put_int(int);" functions and call them in your code to force the input
    or output effects with minimal generated code.


    Look at the following code:

    Is volatile ct_atomic_word aword = { 0 }; even legal? _______________________________
    #include <iostream>
    #include <cstdint>
    #include <atomic>

    // humm... For certian use cases,
    // volatile might be needed here, say
    // for embeded work, controlling something,
    // ect...

    // or is std::atomic guaranteed to work

    typedef std::uint32_t ct_word;
    typedef std::atomic<ct_word> ct_atomic_word;


    int main()
    {
    -a-a-a ct_atomic_word aword = { 0 };

    -a-a-a // na... but, well, for tricky hardware work?
    -a-a-a // oh yeah. sucks. need that volatile.

    -a-a-a // is this even okay? Used with a std::atomic?
    -a-a-a //volatile ct_atomic_word aword = { 0 };

    -a-a-a {
    -a-a-a-a-a-a-a aword.store(1, std::memory_order_relaxed);
    -a-a-a-a-a-a-a aword.store(2, std::memory_order_relaxed);
    -a-a-a-a-a-a-a aword.store(3, std::memory_order_relaxed);
    -a-a-a }

    -a-a-a std::cout << "aword = " << aword.load(std::memory_order_relaxed) << std::endl;

    -a-a-a return 0;
    }
    _______________________________


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From boltar@boltar@caprica.universe to comp.lang.c++ on Mon May 11 08:28:46 2026
    From Newsgroup: comp.lang.c++

    On Mon, 11 May 2026 08:25:55 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning below is >incorrect - I am not an expert here by any means.

    Whats the point of std::atomic anyway? Just how often does a thread critical section just require the test and set of a single value? And if you do
    want to do that posix semaphores have been a thing since the early 90s
    and SysV ones since at least the 80s if not earlier.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Mon May 11 11:02:19 2026
    From Newsgroup: comp.lang.c++

    On 11/05/2026 10:28, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 08:25:55 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning below
    is incorrect - I am not an expert here by any means.

    Whats the point of std::atomic anyway? Just how often does a thread
    critical
    section just require the test and set of a single value? And if you do
    want to do that posix semaphores have been a thing since the early 90s
    and SysV ones since at least the 80s if not earlier.


    Atomics are for shared information /without/ needing semaphores,
    critical sections or other more expensive operations. Read up about non-blocking or lock-free algorithms.


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Fred. Zwarts@F.Zwarts@HetNet.nl to comp.lang.c++ on Mon May 11 11:46:18 2026
    From Newsgroup: comp.lang.c++

    Op 11.mei.2026 om 06:51 schreef Chris M. Thomasson:
    Well, how much god damn optimization is a 100% conforming compiler
    allowed to do on my std::atomics?

    Can they be used as if they are "volatile", or not, damn seems not...?
    If I make three atomic stores, I better get those three atomic stores in
    my generated ASM or something, damn it!

    But, I am not 100% sure this is guaranteed unless another thread is in there. I know every std::atomic impl I have seen is laced with volatile somewhere. But, is it required to be? Or, well, shit.

    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.

    Look at the following code:

    Is volatile ct_atomic_word aword = { 0 }; even legal? _______________________________
    #include <iostream>
    #include <cstdint>
    #include <atomic>

    // humm... For certian use cases,
    // volatile might be needed here, say
    // for embeded work, controlling something,
    // ect...

    // or is std::atomic guaranteed to work

    typedef std::uint32_t ct_word;
    typedef std::atomic<ct_word> ct_atomic_word;


    int main()
    {
    -a-a-a ct_atomic_word aword = { 0 };

    -a-a-a // na... but, well, for tricky hardware work?
    -a-a-a // oh yeah. sucks. need that volatile.

    -a-a-a // is this even okay? Used with a std::atomic?
    -a-a-a //volatile ct_atomic_word aword = { 0 };

    -a-a-a {
    -a-a-a-a-a-a-a aword.store(1, std::memory_order_relaxed);
    -a-a-a-a-a-a-a aword.store(2, std::memory_order_relaxed);
    -a-a-a-a-a-a-a aword.store(3, std::memory_order_relaxed);
    -a-a-a }

    -a-a-a std::cout << "aword = " << aword.load(std::memory_order_relaxed) << std::endl;

    -a-a-a return 0;
    }
    _______________________________


    As I understand it, volatile and atomic serve different purposes
    (although they could use the same mechanism).

    Volatile must be used to indicate that the contents of a location may
    change by other means than the program code, e.g., a I/O register of a
    device. The consequence is that reading the location may not be removed
    by optimisation. It usually also has the effect that writing the
    location is not postponed.

    Atomic must be used to make sure that the access to a location that
    needs multiple steps is not interrupted by other threads that access the
    same location. If the compiler is able to conclude that no such other
    thread can do this (e.g., because there is only one thread in the
    program) reading the location could be optimised away if the contents is already known, or writing could be postponed if another write happens
    somewhat later, because it has no observable effects

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Mon May 11 12:40:37 2026
    From Newsgroup: comp.lang.c++

    On 11/05/2026 11:46, Fred. Zwarts wrote:


    As I understand it, volatile and atomic serve different purposes
    (although they could use the same mechanism).

    Yes.


    Volatile must be used to indicate that the contents of a location may
    change by other means than the program code, e.g., a I/O register of a device. The consequence is that reading the location may not be removed
    by optimisation. It usually also has the effect that writing the
    location is not postponed.

    That's mostly right. Volatile accesses are reads or writes through
    volatile lvalues (such as either accessing an object declared
    "volatile", or use a pointer-to-volatile). Something other than the
    code may read or change the volatile object, or there can be other
    effects triggered by the read or write. (For hardware registers, you
    might, for example, have an event flag register that is cleared when it
    is read.)

    The other critical point about volatile accesses is that they must
    follow program order - but only as viewed by the current thread.
    Normally reads and writes to memory can be re-ordered as convenient for
    the compiler, and combined or eliminated if doing so does not affect the meaning of the program. Volatile accesses cannot be re-ordered with
    respect to other volatile accesses - but they /can/ be re-ordered with
    respect to non-volatile accesses. And other threads may see the
    volatile accesses in a different order.


    Atomic must be used to make sure that the access to a location that
    needs multiple steps is not interrupted by other threads that access the same location. If the compiler is able to conclude that no such other
    thread can do this (e.g., because there is only one thread in the
    program) reading the location could be optimised away if the contents is already known, or writing could be postponed if another write happens somewhat later, because it has no observable effects


    The first major point of an atomic access is that any other thread will
    see the world before the access, or the world after the access - it will
    never see the access half-done. So if you have atomic fetch-and-add of
    one happening in two threads on the same address, each thread will see
    the atomic variable either before the other thread's operation starts,
    or after it has finished - so you are guaranteed that both addition
    operations occur.

    The second major point of atomics is that they can have specified memory orderings that affect how other threads see potential re-ordering of
    memory operations - including non-atomic operations.

    Note that processors have a set of sizes for which their load and store operations are atomic anyway - typically on modern processors all 64-bit
    or smaller loads and stores are atomic without any special treatment.
    (On an 8-bit processor, on the other hand, a 32-bit load or store would
    not be atomic without extra work.) So if you have a 32-bit atomic load
    or store with memory order "relaxed" (i.e., no requirements for synchronisation with other threads), then I don't think there is any difference from just a normal 32-bit load or store.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris Ahlstrom@OFeem1987@teleworm.us to comp.lang.c++ on Mon May 11 06:55:05 2026
    From Newsgroup: comp.lang.c++

    David Brown wrote this screed in ALL-CAPS:

    On 11/05/2026 11:46, Fred. Zwarts wrote:

    As I understand it, volatile and atomic serve different purposes
    (although they could use the same mechanism).

    Yes.

    Volatile must be used to indicate that the contents of a location may
    change by other means than the program code, e.g., a I/O register of a
    device. The consequence is that reading the location may not be removed
    by optimisation. It usually also has the effect that writing the
    location is not postponed.

    That's mostly right. Volatile accesses are reads or writes through
    volatile lvalues (such as either accessing an object declared
    "volatile", or use a pointer-to-volatile). Something other than the
    code may read or change the volatile object, or there can be other
    effects triggered by the read or write. (For hardware registers, you
    might, for example, have an event flag register that is cleared when it
    is read.)

    The other critical point about volatile accesses is that they must
    follow program order - but only as viewed by the current thread.
    Normally reads and writes to memory can be re-ordered as convenient for
    the compiler, and combined or eliminated if doing so does not affect the meaning of the program. Volatile accesses cannot be re-ordered with
    respect to other volatile accesses - but they /can/ be re-ordered with respect to non-volatile accesses. And other threads may see the
    volatile accesses in a different order.

    Atomic must be used to make sure that the access to a location that
    needs multiple steps is not interrupted by other threads that access the
    same location. If the compiler is able to conclude that no such other
    thread can do this (e.g., because there is only one thread in the
    program) reading the location could be optimised away if the contents is
    already known, or writing could be postponed if another write happens
    somewhat later, because it has no observable effects

    The first major point of an atomic access is that any other thread will
    see the world before the access, or the world after the access - it will never see the access half-done. So if you have atomic fetch-and-add of
    one happening in two threads on the same address, each thread will see
    the atomic variable either before the other thread's operation starts,
    or after it has finished - so you are guaranteed that both addition operations occur.

    The second major point of atomics is that they can have specified memory orderings that affect how other threads see potential re-ordering of
    memory operations - including non-atomic operations.

    Note that processors have a set of sizes for which their load and store operations are atomic anyway - typically on modern processors all 64-bit
    or smaller loads and stores are atomic without any special treatment.
    (On an 8-bit processor, on the other hand, a 32-bit load or store would
    not be atomic without extra work.) So if you have a 32-bit atomic load
    or store with memory order "relaxed" (i.e., no requirements for synchronisation with other threads), then I don't think there is any difference from just a normal 32-bit load or store.

    I thought this was a newsgroup about C++.

    < ducks and runs :-) >
    --
    How do I type "for i in *.dvi do xdvi $i done" in a GUI?
    -- Discussion in comp.os.linux.misc on the intuitiveness of interfaces
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From boltar@boltar@caprica.universe to comp.lang.c++ on Mon May 11 10:59:09 2026
    From Newsgroup: comp.lang.c++

    On Mon, 11 May 2026 11:02:19 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 10:28, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 08:25:55 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning below
    is incorrect - I am not an expert here by any means.

    Whats the point of std::atomic anyway? Just how often does a thread
    critical
    section just require the test and set of a single value? And if you do
    want to do that posix semaphores have been a thing since the early 90s
    and SysV ones since at least the 80s if not earlier.


    Atomics are for shared information /without/ needing semaphores,

    The underlying implementation will be the same.

    critical sections or other more expensive operations. Read up about >non-blocking or lock-free algorithms.

    An atomic/semaphore is just a lock on a single value by another name.
    Also IIRC the "+=" operation isn't atomic with std::atomic which is a bit
    of a joke.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Mon May 11 13:20:17 2026
    From Newsgroup: comp.lang.c++

    On 11/05/2026 12:59, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 11:02:19 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 10:28, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 08:25:55 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning
    below is incorrect - I am not an expert here by any means.

    Whats the point of std::atomic anyway? Just how often does a thread
    critical
    section just require the test and set of a single value? And if you do
    want to do that posix semaphores have been a thing since the early 90s
    and SysV ones since at least the 80s if not earlier.


    Atomics are for shared information /without/ needing semaphores,

    The underlying implementation will be the same.

    <https://cppreference.com/cpp/thread#Semaphores> <https://cppreference.com/cpp/atomic/atomic>

    I don't know how you can see them as being similar, unless by "the
    underlying mechanism" you mean memory accesses along with
    processor-specific features like bus lock prefixes, load-locked/store-conditional sequences, CAS operations, memory barrier instructions, etc.

    In particular, semaphores have blocking support - you can block until a semaphore is available. Atomics do not block, and are critical to non-blocking algorithms.


    critical sections or other more expensive operations.-a Read up about
    non-blocking or lock-free algorithms.

    An atomic/semaphore is just a lock on a single value by another name.

    Neither of them are locks.

    Also IIRC the "+=" operation isn't atomic with std::atomic which is a bit
    of a joke.


    The operator "+=" on std::atomic integer and pointer types is defined as "fetch_add(arg) + arg" - the operation on the atomic variable is atomic.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Mon May 11 13:21:49 2026
    From Newsgroup: comp.lang.c++

    Am 11.05.2026 um 12:59 schrieb boltar@caprica.universe:

    An atomic/semaphore is just a lock on a single value by another name.
    Also IIRC the "+=" operation isn't atomic with std::atomic which is
    a bit of a joke.
    It is a atomic. But the memory-ordering is fixed to memory_order_seq_cst.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Mon May 11 13:22:41 2026
    From Newsgroup: comp.lang.c++

    Am 11.05.2026 um 13:20 schrieb David Brown:

    In particular, semaphores have blocking support - you can block until a semaphore is available.-a Atomics do not block, and are critical to non- blocking algorithms.

    You can have a futex'd ::wait() on an atomic.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From cross@cross@spitfire.i.gajendra.net (Dan Cross) to comp.lang.c++ on Mon May 11 11:53:10 2026
    From Newsgroup: comp.lang.c++

    In article <10ts5ur$updt$2@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    On 11/05/2026 10:28, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 08:25:55 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning below
    is incorrect - I am not an expert here by any means.

    Whats the point of std::atomic anyway? Just how often does a thread
    critical
    section just require the test and set of a single value? And if you do
    want to do that posix semaphores have been a thing since the early 90s
    and SysV ones since at least the 80s if not earlier.


    Atomics are for shared information /without/ needing semaphores,
    critical sections or other more expensive operations. Read up about >non-blocking or lock-free algorithms.

    And also for implementing such things.

    - Dan C.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Mon May 11 15:18:00 2026
    From Newsgroup: comp.lang.c++

    On 11/05/2026 13:53, Dan Cross wrote:
    In article <10ts5ur$updt$2@dont-email.me>,
    David Brown <david.brown@hesbynett.no> wrote:
    On 11/05/2026 10:28, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 08:25:55 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning below
    is incorrect - I am not an expert here by any means.

    Whats the point of std::atomic anyway? Just how often does a thread
    critical
    section just require the test and set of a single value? And if you do
    want to do that posix semaphores have been a thing since the early 90s
    and SysV ones since at least the 80s if not earlier.


    Atomics are for shared information /without/ needing semaphores,
    critical sections or other more expensive operations. Read up about
    non-blocking or lock-free algorithms.

    And also for implementing such things.


    Indeed. Both volatiles and atomics (or volatile atomics) are useful in
    the implementation of semaphores and other kinds of synchronisation,
    locking, and concurrency types. Standard atomics reduce the need for compile-specific extensions.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Mon May 11 15:20:05 2026
    From Newsgroup: comp.lang.c++

    Am 11.05.2026 um 15:18 schrieb David Brown:

    Indeed.-a Both volatiles and atomics (or volatile atomics) are useful in
    the implementation of semaphores and other kinds of synchronisation, locking, and concurrency types. ...

    volatile doesn't make sense for that purpose.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From boltar@boltar@caprica.universe to comp.lang.c++ on Mon May 11 15:08:03 2026
    From Newsgroup: comp.lang.c++

    On Mon, 11 May 2026 13:20:17 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 12:59, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 11:02:19 +0200
    The underlying implementation will be the same.

    <https://cppreference.com/cpp/thread#Semaphores> ><https://cppreference.com/cpp/atomic/atomic>

    I don't know how you can see them as being similar, unless by "the >underlying mechanism" you mean memory accesses along with
    processor-specific features like bus lock prefixes, >load-locked/store-conditional sequences, CAS operations, memory barrier >instructions, etc.

    Nice cut and paste. Yes, I'm talking about the CPU level.

    In particular, semaphores have blocking support - you can block until a >semaphore is available. Atomics do not block, and are critical to >non-blocking algorithms.

    And? Semaphores don't have to block.

    critical sections or other more expensive operations.-a Read up about
    non-blocking or lock-free algorithms.

    An atomic/semaphore is just a lock on a single value by another name.

    Neither of them are locks.

    They're locks in the sense that nothing else can touch the value while the current thread is updating it. So if another thread tries it'll be blocked.
    You can call it what you like but locking seems a good enough word to me.

    Also IIRC the "+=" operation isn't atomic with std::atomic which is a bit
    of a joke.


    The operator "+=" on std::atomic integer and pointer types is defined as >"fetch_add(arg) + arg" - the operation on the atomic variable is atomic.

    Its not atomic at the code level so its effectively useless.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c++ on Mon May 11 15:48:08 2026
    From Newsgroup: comp.lang.c++

    David Brown <david.brown@hesbynett.no> writes:
    On 11/05/2026 12:59, boltar@caprica.universe wrote:


    Atomics are for shared information /without/ needing semaphores,

    The underlying implementation will be the same.

    That depends entirely on the instruction set of the target
    processor. Most of the modern architectures include
    instructions to atomically modify a location in memory
    (e.g. Fetch-and-add). This is far more efficient
    than attempting to acquire a spinlock or posix mutex
    simply to update a single location in memory,
    particularly when there are a significant number
    of contenders (e.g. on a 128-core CPU).

    This is essentially free in systems with
    processor memory caching, since only one
    processor (hardware thread) can own a cache line for write
    access at any point in time. The processor
    simply sends the atomic op directly to the cache
    (or if caches are bypassed, the memory controller)
    for execution.

    Those operations have been extended such that
    modern hardware supports that level of atomicity
    across PCI express and other interconnect
    technologies.

    The advantage of the cache coherency algorithm
    efficiency vs LL/SC or LDEX/STREX is very signficiant.

    ARM, for example, has atomic:

    - load and add (LDADD)
    - load and exclusive or (LDEOR)
    - load and clear bit (LDCLR)
    - load and set bit (LDSET)
    - load and return minimum value
    - load and return maximum value
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c++ on Mon May 11 15:49:06 2026
    From Newsgroup: comp.lang.c++

    "Fred. Zwarts" <F.Zwarts@HetNet.nl> writes:
    Op 11.mei.2026 om 06:51 schreef Chris M. Thomasson:

    As I understand it, volatile and atomic serve different purposes
    (although they could use the same mechanism).

    volatile restricts the compiler from making certain
    optimizations.

    atomics are implemented by the hardware.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Mon May 11 12:36:56 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 8:49 AM, Scott Lurndal wrote:
    "Fred. Zwarts" <F.Zwarts@HetNet.nl> writes:
    Op 11.mei.2026 om 06:51 schreef Chris M. Thomasson:

    As I understand it, volatile and atomic serve different purposes
    (although they could use the same mechanism).

    volatile restricts the compiler from making certain
    optimizations.

    atomics are implemented by the hardware.

    Is:

    volatile ct_atomic_word aword = { 0 };

    even legal C++?
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Mon May 11 12:48:53 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 3:59 AM, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 11:02:19 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 10:28, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 08:25:55 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 06:51, Chris M. Thomasson wrote:
    Well, damn. It seems that std::atomic might not be sufficient, and
    volatile needs to be used.


    I very much hope to be corrected if someone thinks my reasoning
    below is incorrect - I am not an expert here by any means.

    Whats the point of std::atomic anyway? Just how often does a thread
    critical
    section just require the test and set of a single value? And if you do
    want to do that posix semaphores have been a thing since the early 90s
    and SysV ones since at least the 80s if not earlier.


    Atomics are for shared information /without/ needing semaphores,

    The underlying implementation will be the same.

    critical sections or other more expensive operations.-a Read up about
    non-blocking or lock-free algorithms.

    An atomic/semaphore is just a lock on a single value by another name.

    Take a deep look at:

    https://en.cppreference.com/cpp/atomic/atomic/is_lock_free

    https://en.cppreference.com/cpp/atomic/atomic/is_always_lock_free

    https://en.cppreference.com/cpp/atomic/atomic_is_lock_free

    The _fun_ part:

    Expands to an integer constant expression with value
    0 for the built-in atomic types that are never lock-free,
    1 for the built-in atomic types that are sometimes lock-free,
    2 for the built-in atomic types that are always lock-free.

    sometimes is fun. wow....

    Fwiw, you can mock up an atomic type that is never lock-free using
    hashing into a lock table.

    (read all) https://groups.google.com/g/comp.lang.c++/c/sV4WC_cBb9Q/m/SkSqpSxGCAAJ



    Also IIRC the "+=" operation isn't atomic with std::atomic which is a bit
    of a joke.


    Ever heard of fetch_and_add? The impl can use an atomic RMW for it.


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Mon May 11 12:54:39 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 6:20 AM, Bonita Montero wrote:
    Am 11.05.2026 um 15:18 schrieb David Brown:

    Indeed.-a Both volatiles and atomics (or volatile atomics) are useful
    in the implementation of semaphores and other kinds of
    synchronisation, locking, and concurrency types. ...

    volatile doesn't make sense for that purpose.


    What if you wanted std atomics that are 100% lock-free ala say, oh:

    https://en.cppreference.com/cpp/atomic/atomic/is_lock_free

    with volatile access to drive something that is outside the scope of the program. std::thread aside for a moment.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Mon May 11 13:00:36 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 4:22 AM, Bonita Montero wrote:
    Am 11.05.2026 um 13:20 schrieb David Brown:

    In particular, semaphores have blocking support - you can block until
    a semaphore is available.-a Atomics do not block, and are critical to
    non- blocking algorithms.

    You can have a futex'd ::wait() on an atomic.


    Yup. That's actually pretty neat for the std to support that.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Mon May 11 13:09:43 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 8:48 AM, Scott Lurndal wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 11/05/2026 12:59, boltar@caprica.universe wrote:


    Atomics are for shared information /without/ needing semaphores,

    The underlying implementation will be the same.

    That depends entirely on the instruction set of the target
    processor. Most of the modern architectures include
    instructions to atomically modify a location in memory
    (e.g. Fetch-and-add). This is far more efficient
    than attempting to acquire a spinlock or posix mutex
    simply to update a single location in memory,
    particularly when there are a significant number
    of contenders (e.g. on a 128-core CPU).

    This is essentially free in systems with
    processor memory caching, since only one
    processor (hardware thread) can own a cache line for write
    access at any point in time. The processor
    simply sends the atomic op directly to the cache
    (or if caches are bypassed, the memory controller)
    for execution.

    Those operations have been extended such that
    modern hardware supports that level of atomicity
    across PCI express and other interconnect
    technologies.

    The advantage of the cache coherency algorithm
    efficiency vs LL/SC or LDEX/STREX is very signficiant.

    ARM, for example, has atomic:

    - load and add (LDADD)
    - load and exclusive or (LDEOR)
    - load and clear bit (LDCLR)
    - load and set bit (LDSET)
    - load and return minimum value
    - load and return maximum value

    Is neat that ARM supports LL/SC _and_ the atomic RMW's.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Mon May 11 22:19:04 2026
    From Newsgroup: comp.lang.c++

    On 11/05/2026 17:08, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 13:20:17 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 12:59, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 11:02:19 +0200
    The underlying implementation will be the same.

    <https://cppreference.com/cpp/thread#Semaphores>
    <https://cppreference.com/cpp/atomic/atomic>

    I don't know how you can see them as being similar, unless by "the
    underlying mechanism" you mean memory accesses along with processor-
    specific features like bus lock prefixes, load-locked/store-
    conditional sequences, CAS operations, memory barrier instructions, etc.

    Nice cut and paste. Yes, I'm talking about the CPU level.

    In particular, semaphores have blocking support - you can block until
    a semaphore is available.-a Atomics do not block, and are critical to
    non-blocking algorithms.

    And? Semaphores don't have to block.

    Of course you don't /have/ to block on a semaphore, but there's not much
    use of them if you don't. You might as well just use an atomic counter,
    which is much cheaper.

    You can't use an atomic object for blocking. C++ has a nice interface
    that appears to do so, but it's actually using a futex or similar
    mechanism for the blocking. Remember, an atomic int takes 4 bytes of
    space (on most platforms), just like an int, and a relaxed read or write
    is just a normal load or store - something that can block needs queues
    of blocked threads and OS calls. They are different worlds.


    critical sections or other more expensive operations.-a Read up about >>>> non-blocking or lock-free algorithms.

    An atomic/semaphore is just a lock on a single value by another name.

    Neither of them are locks.

    They're locks in the sense that nothing else can touch the value while the current thread is updating it. So if another thread tries it'll be blocked. You can call it what you like but locking seems a good enough word to me.


    That is not what anyone else means by locks (in this context). A lock
    is something you use to control access to something else - not just to
    the single object.

    Also IIRC the "+=" operation isn't atomic with std::atomic which is a
    bit
    of a joke.


    The operator "+=" on std::atomic integer and pointer types is defined
    as "fetch_add(arg) + arg" - the operation on the atomic variable is
    atomic.

    Its not atomic at the code level so its effectively useless.


    That makes no sense at all. "Atomic" does not mean "uses one assembly instruction".


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Mon May 11 13:25:56 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 1:19 PM, David Brown wrote:
    On 11/05/2026 17:08, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 13:20:17 +0200
    David Brown <david.brown@hesbynett.no> gabbled:
    On 11/05/2026 12:59, boltar@caprica.universe wrote:
    On Mon, 11 May 2026 11:02:19 +0200
    The underlying implementation will be the same.

    <https://cppreference.com/cpp/thread#Semaphores>
    <https://cppreference.com/cpp/atomic/atomic>

    I don't know how you can see them as being similar, unless by "the
    underlying mechanism" you mean memory accesses along with processor-
    specific features like bus lock prefixes, load-locked/store-
    conditional sequences, CAS operations, memory barrier instructions, etc.

    Nice cut and paste. Yes, I'm talking about the CPU level.

    In particular, semaphores have blocking support - you can block until
    a semaphore is available.-a Atomics do not block, and are critical to
    non-blocking algorithms.

    And? Semaphores don't have to block.

    Of course you don't /have/ to block on a semaphore, but there's not much
    use of them if you don't.-a You might as well just use an atomic counter, which is much cheaper.

    You can't use an atomic object for blocking.-a C++ has a nice interface
    that appears to do so, but it's actually using a futex or similar
    mechanism for the blocking.

    Yeah. "Ideally", the futex is 100% separated from the atomics wrt its
    blocking logic. Usually hashed tables of wait queues in the kernel or wherever. For an impl detail, say the atomic can use a pointer to itself
    as a means to hash itself into a waitqueue. Kind of akin to:

    https://groups.google.com/g/comp.lang.c++/c/sV4WC_cBb9Q/m/SkSqpSxGCAAJ



    Remember, an atomic int takes 4 bytes of
    space (on most platforms), just like an int, and a relaxed read or write
    is just a normal load or store - something that can block needs queues
    of blocked threads and OS calls.-a They are different worlds.


    [...]
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From red floyd@no.spam.here@its.invalid to comp.lang.c++ on Mon May 11 21:04:33 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 12:48 PM, Chris M. Thomasson wrote:
    [redacted]
    https://en.cppreference.com/cpp/atomic/atomic/is_lock_free

    https://en.cppreference.com/cpp/atomic/atomic/is_always_lock_free

    https://en.cppreference.com/cpp/atomic/atomic_is_lock_free

    The _fun_ part:

    Expands to an integer constant expression with value
    0 for the built-in atomic types that are never lock-free,
    1 for the built-in atomic types that are sometimes lock-free,
    2 for the built-in atomic types that are always lock-free.

    Would have been nice to have:

    -1 = sometimes
    0 = never
    1 = always

    So that the spaceship operator could be used.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Tue May 12 12:14:26 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 3:55 AM, Chris Ahlstrom wrote:
    David Brown wrote this screed in ALL-CAPS:

    On 11/05/2026 11:46, Fred. Zwarts wrote:
    [...
    I thought this was a newsgroup about C++.

    < ducks and runs :-) >

    Why run? It is about C++. :^)

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Chris M. Thomasson@chris.m.thomasson.1@gmail.com to comp.lang.c++ on Thu May 14 00:35:12 2026
    From Newsgroup: comp.lang.c++

    On 5/11/2026 9:04 PM, red floyd wrote:
    On 5/11/2026 12:48 PM, Chris M. Thomasson wrote:
    [redacted]
    https://en.cppreference.com/cpp/atomic/atomic/is_lock_free

    https://en.cppreference.com/cpp/atomic/atomic/is_always_lock_free

    https://en.cppreference.com/cpp/atomic/atomic_is_lock_free

    The _fun_ part:

    Expands to an integer constant expression with value
    0 for the built-in atomic types that are never lock-free,
    1 for the built-in atomic types that are sometimes lock-free,
    2 for the built-in atomic types that are always lock-free.

    Would have been nice to have:

    -1 = sometimes
    -a0 = never
    -a1 = always

    So that the spaceship operator could be used.


    Shit man, been a while since I used the sucker!
    --- Synchronet 3.22a-Linux NewsLink 1.2