dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Fri Jun 18, 2021 5:38 pm

maybe pointless to you, to me it's expedient. But to argue with me about it is pointless. :mrgreen:

Heater
Posts: 18344
Joined: Tue Jul 17, 2012 3:02 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Fri Jun 18, 2021 6:53 pm

tttapa wrote:
Fri Jun 18, 2021 5:32 pm
I referred to this section in en.cppreference.com/w/cpp/atomic/atomic:
(since C++23)
The compatibility macro _Atomic is provided in <stdatomic.h> such that _Atomic(T) is identical to std::atomic<T> while both are well-formed.
It'll allow you to use C header files that contain declarations of _Atomic variables, arguments or return types in C++ code, but it still doesn't necessarily allow you to write code with that's valid C and C++ at the same time (which is pointless IMO).
Intersting.

So if I I have a _Atomic in C and I somehow get hold of it it C++ I can cast it as a std::atomic<T> and use it.

Presumably because under the hood, when it comes down to machine code, they are the same thing.

Do I even need to cast it, can I use it as is?

Sounds like a mess to be avoided anyway.
Memory in C++ is a leaky abstraction .

LdB
Posts: 1703
Joined: Wed Dec 07, 2016 2:29 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 6:55 am

I am not getting involved in yet another long winded ridiculous discussion so I will keep this brief.

At the end of the day you are dealing with a lock primitive and there are very limited ways to do it on a given CPU architecture, the language is just a construct to the assembler code you need.

dsyleixa what isn't clear in your code is if you are trying to build a mutex, semphore or a signal
In your example codes you don't actually wait on anything or concurrently do anything so it is up in air as to what you are after.

You need a lock for 1 of 2 reasons
Efficiency: Taking a lock saves you from doing the same work again on pthreads usually that would mean sleeping the task so you don't use CPU time
Correctness: Taking a lock prevents concurrent access

There is no way to work out from your example why you want the lock ... you would need to spell it out.

Now as a final point there are strange situations you need volatile atomics which are for hardware lock or distributed lock manager (on a CPU cluster). Volatile has it's specific meaning and having an atomic does not change that function.

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 8:02 am

as stated, I have _Atomic working for C (the partially false, ambiguous, or misleading claims from another topic could be corrected), I can also use mutexes if I want or need, and I abandoned the rest as there apparently is no atomic C/C++ code cross compatibility. Nonetheless I'm eventually fine with all that.

tttapa
Posts: 65
Joined: Mon Apr 06, 2020 2:52 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 11:45 am

Heater wrote:
Fri Jun 18, 2021 6:53 pm
So if I I have a _Atomic in C and I somehow get hold of it it C++ I can cast it as a std::atomic<T> and use it.
The way I interpret the documentation, you don't even have to cast. If you have a C header with

Code: Select all

#include <stdatomic.h>
#ifdef _cplusplus
extern "C"
#endif
void do_something(_Atomic(int) *x);
then the C compiler sees `void do_something(_Atomic(int) *x)` and the C++ compiler sees `extern "C" void do_something(std::atomic<int> *x)`, so no casts necessary. Given that compilers are encouraged to use the same representation for C and C++ atomics, this should work fine.
However, you'd have to look at the proposal (http://www.open-std.org/jtc1/sc22/wg21/ ... 943r6.html) to be absolutely sure, this seems like a pretty exotic use case at the boundary of languages ...
At the time of writing, none of the major compilers has implemented this feature: https://en.cppreference.com/w/cpp/compi ... y_features
LdB wrote: Now as a final point there are strange situations you need volatile atomics which are for hardware lock or distributed lock manager (on a CPU cluster). Volatile has it's specific meaning and having an atomic does not change that function.
Do you have any specific examples where you need `volatile atomic<T>`? Is this ever used in user space code, or is it something you only really need when dealing with hardware and interrupts directly?

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 12:15 pm

Do you have any specific examples where you need `volatile atomic<T>`? Is this ever used in user space code, or is it something you only really need when dealing with hardware and interrupts directly?
now this is interesting, it actually is similar to what I even already asked above, not answered yet though:
Given I have sort of "semaphore"
_Atomic bool ThreadsRun=true;
and thread functions like (sketched from the free hand)

Code: Select all

#include <pthread.h>
#include <stdio.h>
#include <wiringPi.h>
#incluse <stdatomic.h>

_Atomic bool ThreadsRun=true;

//...
void *foo (void*) {
  while(ThreadsRun) {
    ThreadsRun=digitalRead(26);
    delay(1);
  }

}

void *bas (void*) {
  static int t=0;
  while(ThreadsRun) {
     printf("%d \n", t++);
     delay(100);
  }
}

int main() {
  wiringPiSetupGpio();
  pthread_t thread0, thread1;
  //...
        
  pthread_create(&thread0, NULL, foo, NULL);
  pthread_create(&thread1, NULL, bas, NULL);
  
  pthread_join(thread0, NULL);
  pthread_join(thread1, NULL);
  
  return 0;
}
will that require a volatile additionally to _Atomic? (this is actually why I used volatile so far)

edited, typos

tttapa
Posts: 65
Joined: Mon Apr 06, 2020 2:52 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 12:51 pm

dsyleixa123 wrote:
Sun Jun 20, 2021 12:15 pm
will that require a volatile additionally to _Atomic? (this is actually why I used volatile so far)
This has been answered multiple times: normal variables that are shared between threads should just be atomic, not volatile.

Volatile tells the compiler that reads/writes to a variable should be assumed to have side effects, so they cannot be reordered or optimized out. Other than that, the meaning of volatile is mostly implementation-defined.
Volatile is used in signal handlers, interrupts, memory mapped IO registers, and so on, which are all things at the boundary or outside of the control of the C++ program, as all of those involve interactions with the operating system and the hardware.
Just reading or writing to a shared variable from different threads happens completely inside of your C++ program, there are no outside effects, and you shouldn't use volatile.

Volatile atomics do exist, and I'm sure there are good reasons to use them in very specific, low-level use cases, but I haven't come across any correct usage of volatile atomics yet.
I hope LdB might be able to shine some light on that or point to specific applications in the context of hardware locks or DLMs.

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 12:55 pm

I know that for normal thread-shared variables, but you mentioned the "hardware" criterium, and in my case the variable is triggered by hardware, that's why I asked.

LdB
Posts: 1703
Joined: Wed Dec 07, 2016 2:29 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 1:11 pm

dsyleixa123 wrote:
Sun Jun 20, 2021 12:15 pm
will that require a volatile additionally to _Atomic? (this is actually why I used volatile so far)
As I said hardware locks and cluster locks have the issue ... atomicity has zero to do with optimizer visibility.

Volatile is an instruction to the optimizer to stay out of it
Currently depending on compiler/hardware there is lots of flex about if two atomic operations can be optimized and there are arguments both ways.

See discusssion
http://www.open-std.org/jtc1/sc22/wg21/ ... ze-atomics

the bottom line
Atomic operations are unsuitable to express that memory locations can be externally modified. Indeed, volatile (or volatile atomic) should be used in these circumstances.
Read the takeaway from the discussion.

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 1:14 pm

i don't understand your answer, too complicated for my poor English.
Can you please bring it to the point (with respect to "hardware" and "digitaRead(hardwarePin)"), in simple words and short sentences?

tttapa
Posts: 65
Joined: Mon Apr 06, 2020 2:52 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 1:19 pm

dsyleixa123 wrote:
Sun Jun 20, 2021 12:55 pm
I know that for normal thread-shared variables, but you mentioned the "hardware" criterium, and in my case the variable is triggered by hardware, that's why I asked.
There is no direct interaction between the “hardware” IO registers and the `ThreadsRun` variable. It is your C program that is writing to the `ThreadsRun` variable, not the hardware.

Eventually, all user input such as key presses comes from “the hardware”, but that doesn't mean that any variable that deals with user input should be marked volatile. The same is true for the `digitalRead` function: there will be some low-level code deep in the wiringPi library/driver that reads the right GPIO register through a volatile pointer, but `digitalRead` just returns a normal `int` (bool? enum?).
LdB wrote:As I said hardware locks and cluster locks have the issue.
Could you elaborate or point to a specific resource? Googling "hardware lock" in combination with volatile or atomic seems to yield unrelated results.

LdB
Posts: 1703
Joined: Wed Dec 07, 2016 2:29 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 2:08 pm

Don't be lazy google "hardware synchronized multi-core processor"

Where I first ran across it was with Xilinx FPGA soft cores where the designer used a "xilinx mutex"
https://www.xilinx.com/products/intelle ... mutex.html
Dates back to the old microblaze softcore.

NXP also has one I have seen in designs
https://www.nxp.com/docs/en/application-note/AN4805.pdf

The code to access to the hardware is usually in std_atomic it just read/writes to a port it's like read/writing a modem status
So same as reading a modem status you may need volatile.

I should add on most of those soft-cores there is rarely any atomic software instructions because they have a state machine on the ALU to keep it simple and almost everything is multi-clock even a nop is often 2 cycles.

Heater
Posts: 18344
Joined: Tue Jul 17, 2012 3:02 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 3:08 pm

dsyleixa123 wrote:
Sun Jun 20, 2021 1:14 pm
i don't understand your answer, too complicated for my poor English.
Can you please bring it to the point (with respect to "hardware" and "digitaRead(hardwarePin)"), in simple words and short sentences?
The bottom line is this is complicated. And a complication that you should not need to worry about.

If you are making direct access to hardware registers you use "volatile" to ensure the compiler optimiser does not optimise away your code. For example.

Code: Select all

// A pointer to some address which is not in memory but rather a hardware register.
unit32_t* some_register = (uint32_t*) 0x10000001;

// Write something to the register
*some_regster = 0x00000002;
In this code "some_register" is not used elsewhere in your code. As it has no effect on your program the optimiser may well optimise it away completely. To avoid this use "volatile". As described here: https://barrgroup.com/embedded-systems/ ... le-keyword and all over the place.

If you are exchanging data with threads in your program then use atomics and/or Mutexs as discussed here since a long time now.

As noted above, if you are using a library that provides I/O functions like "digitalRead" you don't need "volatile" anywhere. That should be taken care of by the library, assuming it is making direct hardware register access rather than making use of some kernel provided interface.

And just to be sure: Don't use "volatile" for syncing data between threads.
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 5:04 pm

yes, thanks, I already understood it from tttapa's reply.

other question,
for C++
#include <atomic>
using namespace std;
static atomic_int myval (42);

why does this work:
myval |= 7;

but not this:
myval /= 7; // compile error!
:?:

User avatar
jahboater
Posts: 7158
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 5:08 pm

Heater wrote:
Sun Jun 20, 2021 3:08 pm
In this code "some_register" is not used elsewhere in your code. As it has no effect on your program the optimiser may well optimise it away completely. To avoid this use "volatile". As described here: https://barrgroup.com/embedded-systems/ ... le-keyword and all over the place.
As a general thing, compilers like to keep variables in registers wherever possible.
That's because retrieving a variable from memory is very very slow.

On a machine such as the Pi4 in 64-bit mode, there are a huge number of registers, and most local variables never get stored in memory ever.

That's no good if the variable is some kind of memory mapped hardware register, whose value could change all the time, outside of your program.
So declaring it volatile tells the compiler to actually read the memory location each and every time it needs to use the variable.
Thus getting the most up to date value.

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 5:12 pm

jahboater wrote:
Sun Jun 20, 2021 5:08 pm
Heater wrote:
Sun Jun 20, 2021 3:08 pm
In this code "some_register" is not used elsewhere in your code. As it has no effect on your program the optimiser may well optimise it away completely. To avoid this use "volatile". As described here: https://barrgroup.com/embedded-systems/ ... le-keyword and all over the place.
As a general thing, compilers like to keep variables in registers wherever possible.
That's because retrieving a variable from memory is very very slow.

On a machine such as the Pi4 in 64-bit mode, there are a huge number of registers, and most local variables never get stored in memory ever.

That's no good if the variable is some kind of memory mapped hardware register whose value could change all the time outside of your program.
So declaring it volatile tells the compiler to actually read the memory location each and every time it needs to use the variable.
Thus getting the most up to date value.
I think that was addressed to me...
yes, I know that too, and that was the initial reason why I was originally using volatile for between threads (which is redundant for between threads though which I meanwhile have learned)

tttapa
Posts: 65
Joined: Mon Apr 06, 2020 2:52 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 6:55 pm

dsyleixa123 wrote:
Sun Jun 20, 2021 5:04 pm
other question,
for C++
#include <atomic>
using namespace std;
static atomic_int myval (42);

why does this work:
myval |= 7;

but not this:
myval /= 7; // compile error!
:?:
I've never come across a situation where I needed an atomic division (or multiplication for that matter), so I'm not sure why you would need it, but you can easily do this using a compare-and-swap (CAS):

Code: Select all

void atomic_div(std::atomic<int> &a, int b) {
    auto a_ = a.load(std::memory_order_relaxed);
    while (!a.compare_exchange_weak(a_, a_ / b));
}
Edit: this is also a topic that's covered on Jeff Preshing's blog, which you could have found using a bit of googling: https://preshing.com/20150402/you-can-d ... operation/

tttapa
Posts: 65
Joined: Mon Apr 06, 2020 2:52 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 7:12 pm

LdB wrote:
Sun Jun 20, 2021 2:08 pm
"hardware synchronized multi-core processor"
https://www.xilinx.com/products/intelle ... mutex.html
https://www.nxp.com/docs/en/application-note/AN4805.pdf

The code to access to the hardware is usually in std_atomic it just read/writes to a port it's like read/writing a modem status
So same as reading a modem status you may need volatile.
Thanks for those pointers. It's not entirely clear to me how you would use them using `std::atomic` (at least NXP seems to have their own C API).

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 8:28 pm

thank you tttapa, I don't actually need atomic division, I just came upon this coincidentally and found it rather odd that one cannot calculate with atomic int like with "basic" int. I had expected "atomic" to be a qualifier like static, volatile or const for either numeric common datatype what it obviously isn't.
Odd, but anyway, it's like it is. (If one had asked me, I had designed atomic also as a qualifier for basic numeric data types, and I also had made C++ a real superset of C (from which it was once created), but who the hell asks me ;-) )

Heater
Posts: 18344
Joined: Tue Jul 17, 2012 3:02 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Sun Jun 20, 2021 11:32 pm

The full joy of concurrency in C++ is skilfully explained here: "Back to Basics: Concurrency - Arthur O'Dwyer - CppCon 2020": https://www.youtube.com/watch?v=F6Ipn7gCOsY

Note the myriad ways simple mistakes can make it all go horribly wrong!
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Mon Jun 21, 2021 7:02 am

yes, I see, that's why I wrote I'll abandon atomic for C++: too weird and too muddled up for my skills.

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 28930
Joined: Sat Jul 30, 2011 7:41 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Mon Jun 21, 2021 7:56 am

dsyleixa123 wrote:
Mon Jun 21, 2021 7:02 am
yes, I see, that's why I wrote I'll abandon atomic for C++: too weird and too muddled up for my skills.
Robust multithreaded code is difficult. C++'s implementation is not weird, or muddled up, it's just a complex subject requiring a complex solution.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Working in the Application's Team.

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Mon Jun 21, 2021 8:24 am

I have to disagree, using mutexes it's not difficult, not complex, still robust, but far less muddled up 8-)

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 28930
Joined: Sat Jul 30, 2011 7:41 pm

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Mon Jun 21, 2021 8:57 am

dsyleixa123 wrote:
Mon Jun 21, 2021 8:24 am
I have to disagree, using mutexes it's not difficult, not complex, still robust, but far less muddled up 8-)
Using mutexes is not difficult, they are an easy to understand concept. Using them to write robust multithreaded code is. Race conditions and deadlocks are good terms to start searching with.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Working in the Application's Team.

dsyleixa123
Posts: 1492
Joined: Mon Jun 11, 2018 11:22 am

Re: atomic or volatile, that is the question ( Whether 'tis nobler in the mind to mutex them)

Mon Jun 21, 2021 9:03 am

that's actually what I meant: I use standard datatypes and mutexes, which to me are easy to understand, to me not difficult to write robust multithreaded code with for my purposes, not complex either, still robust though, but less muddled up to me like C++ atomic.

Return to “C/C++”