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

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

Thu Jun 17, 2021 3:37 pm

new topic, as suggested by jamesh (instead of just deviding the topic in 2):
in another thread it had been claimed that volatile wouldn't be suitable for inter-thread-communication ( viewtopic.php?p=1878460#p1878460, which was actually the 1st off-topic post over there which leaded to some more...) , and e.g. "race conditions" had been cited as an argument - but I have to disagree about that, because race conditions are off-topic here:
If just 1 thread writes to a variable and all other listen, there won't be any a race condition at all, and one may just use volatile variables.
OTOH, if multiple threads write and read arbitrarily, then we can use volatile variables plus mutexes.
So why bother with the incomprehensible and super-cumbersome atomic?

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

Re: atomic or volatile, that is the question

Thu Jun 17, 2021 4:04 pm

The other thread is right, volatile has no place whatsoever in the context of multithreading. Volatile should be used for memory that might change outside of the control of your C++ program, for example memory mapped IO etc. It has nothing to do with inter-thread communication.
dsyleixa123 wrote: "race conditions" had been cited as an argument - but I have to disagree about that, because race conditions are off-topic here:
If just 1 thread writes to a variable and all other listen, there won't be a race condition at all, and one may just use volatile variables.
No, if one thread reads and another thread writes to the same variable, that's a race condition: https://en.cppreference.com/w/cpp/langu ... data_races
When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race unless
  • both evaluations execute on the same thread or in the same signal handler, or
  • both conflicting evaluations are atomic operations (see std::atomic), or
  • one of the conflicting evaluations happens-before another (see std::memory_order)
If a data race occurs, the behavior of the program is undefined.
You have to synchronize access to the shared variable if at least one thread writes to it. Synchronization could be done using `std::mutex`, or by using an atomic variable with the appropriate memory order.
dsyleixa123 wrote: OTOH, if multiple threads write and read arbitrarily, then we can use volatile variables plus mutexes.
Again, volatile has no place here whatsoever, if all accesses to the shared variables are guarded by a mutex, that's sufficient to ensure synchronization, you shouldn't make the shared variables volatile, which has nothing to do with synchronization between threads.
dsyleixa123 wrote: So why bother with the incomprehensible and super-cumbersome atomic?
Because atomics can be faster than mutexes if used correctly. Acquiring or releasing a mutex requires memory barrier instructions, which requires synchronization between different cores, which defeats some of the parallelism you might be aiming for, slow down your program. By using atomics, some loads and stores require less strict barriers, which can be faster.

Atomics are very tricky to get right, so you should probably start with a mutex. Correctness of your program is usually more important than speed, but if you really notice that mutexes are the bottleneck, you could consider lock-free alternatives and atomics. However, this is a very complicated topic that requires advanced knowledge of the C++ standard and the hardware you're working with. Even the best experts struggle with specifying things like `std::memory_order_consume`.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 4:15 pm

Atomics are very tricky to get right, so you should probably start with a mutex.
indeed , that's what I already do, and till now no one could even rework a simple example which has to deal with multiple vague, untold, and ambiguous atomic language definitions plus their syntax:

Code: Select all

#include <stdatomic.h> // needed for ANSI C?
static _Atomic int myval=0;
static _Atomic bool flag=true;
//...
myval=42;
flag=false;
myval|= 7;
OTOH, apart from atomic, volatile still will be needed though even with mutexes so that the compiler won't optimize the variables away or even cashes them.

tttapa
Posts: 66
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)

Thu Jun 17, 2021 4:36 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 4:15 pm
till now no one could even rework a simple example which has to deal with multiple vague, untold, and ambiguous atomic language definitions plus their syntax
Rework which example? What ambiguous definitions?
dsyleixa123 wrote: OTOH, apart from atomic, volatile still will be needed though even with mutexes so that the compiler won't optimize the variables away or even cashes them.
No, you don't need volatile in this case. The C and C++ languages are aware of threads (since C11 and C++11), they won't optimize out variables that might be accessed from another thread.
Acquiring or releasing a mutex, or reading/writing to atomic variables (with the right memory orders) result in the necessary fences to make sure changes propagate through the system's cache, and to prevent the compiler from caching the value in a register.

Volatile is necessary for interrupts and memory mapped IO registers, but not for inter-thread communication.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 4:42 pm

The C and C++ languages are aware of threads (since C11 and C++11), they won't optimize out variables that might be accessed from another thread.
ok, fine, that's good to know about out-optimizing (tbh, not sure if I would bet on that though), but what about cashing e.g. in registers or whereever?
Rework which example? What ambiguous definitions?
the example above and the ambiguous and vague definitions in the provided links - they tell actually nothing comprehensible about usage (if any) in actual code.

tttapa
Posts: 66
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)

Thu Jun 17, 2021 5:09 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 4:42 pm
ok, fine, that's good to know about out-optimizing, but what about cashing e.g. in registers or whereever?
If you aqcuire or release a mutex, the compiler will emit a fence instruction, which causes changes to propagate through the system's cache.

Consider the following example:

Code: Select all

int i = 0; // global, normal variable
std::mutex mtx;

Thread A             Thread B
--------             --------
mtx.lock();
i = 42;
mtx.unlock();       
                     mtx.lock();
                     std::cout << i << std::endl;
                     mtx.unlock();
As long as thread B reads the value of `i` after thread A wrote to it, thread `B` will always read the value `42`, regardless of the cache of the system:
mtx.unlock() in thread A makes all writes before it visible to the rest of the system, so writes before it cannot be reordered after the mtx.unlock(). The mtx.lock() in thread B ensures that all reads after it see the state of the rest of the system as it was when the mutex was locked, the reads after mtx.lock() cannot be reordered before the mtx.lock(). This means that the critical section in thread B always sees all changes that occurred in the critical section of thread A. (If thread B acquires the mutex after thread A released it, if thread B runs before thread A, thread B will print `0` of course.)

This is guaranteed by the C++ standard, caching is an implementation detail. The compiler is not allowed to cache these variables across the `mtx.lock()/unlock()` calls (if that would violate this guarantee).

Note that this is much stronger than the guarantees you get with `volatile`: you basically only have any guarantees about the order with respect to other volatile operations and that each volatile read/write is actually carried out.
Mutexes and atomics also give guarantees about the order of operations, but the order of all operations, and you even get some guarantees about the order between variable accesses from different CPUs, which volatile cannot give you at all.
Furthermore, while volatile allows pretty much no optimizations, there are still some cases where compilers could optimize mutexes and atomics, as long as the guarantees of the Standard still hold after the optimization.
dsyleixa123 wrote: the example above and the ambiguous definitions in the provided links - they tell actually nothing comprehensible about usage (if any) in actual code.
I'm not sure which links you're referring to, but I'd highly recommend Herb Sutter's excellent atomic<> Weapons talks and the following (and more) blog posts by Jeff Preshing:
https://preshing.com/20120710/memory-ba ... perations/
https://preshing.com/20120913/acquire-a ... semantics/
https://preshing.com/20120625/memory-or ... pile-time/

The last one also answers your question about caching.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 5:14 pm

ah, your code is C++, I normally use pthread both for C and for C++ (it's more straight IMO)
and usually for my purposes it doesn't matter if one thread reads whilst another is writing, but if it did, then I would use mutex lock and unlock for both read and write.
Last edited by dsyleixa123 on Thu Jun 17, 2021 5:15 pm, edited 1 time in total.

tttapa
Posts: 66
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)

Thu Jun 17, 2021 5:15 pm

To clarify the example I gave, the compiler is not allowed to transform the code in my previous post into the following:

Code: Select all

int i = 0; // global, normal variable
std::mutex mtx;

Thread A             Thread B
--------             --------
                     int temp_register = i; // read i and cache it in a register
mtx.lock();
i = 42;
mtx.unlock();       
                     mtx.lock();
                     std::cout << temp_register << std::endl;
                     mtx.unlock();
This would violate the guarantee that the read of `i` cannot be reordered before the `mtx.lock()` in thread B.
dsyleixa123 wrote: ah, your code is C++, I normally use pthread both for C and for C++ (it's more straight IMO)
Personally I would disagree, but it doesn't matter, C11 took over the C++11 memory model for atomics and threads.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 5:20 pm

ok, but I don't understand here why there would be no guarantee - the thread which comes first is catching the mutex, the other will have to wait, and I don't understand why this should matter or conflict then.
1st, I would never let i be stored in a register (or let cashe it), that's why I use volatile.
2nd, in the worst case, the reading thread is simply reading the the new value (from the writing thread) just 1 loop later, I wouldn't care about that... :roll:

As to your links:
Too many charactres for my simple code example... :roll:
Last edited by dsyleixa123 on Thu Jun 17, 2021 5:26 pm, edited 1 time in total.

tttapa
Posts: 66
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)

Thu Jun 17, 2021 5:26 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 5:20 pm
but I don't understand here why there would be no guarantee
Which guarantee?

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 5:27 pm

This would violate the guarantee that the read of `i` cannot be reordered before the `mtx.lock()` in thread B.
crossover posted, I added:
"1st, I would never let i be stored in a register (or let cache it either way), that's why I use volatile.
2nd, in the worst case, the reading thread is simply reading the new value (from the writing thread) just 1 loop later, I wouldn't care about that..."

tttapa
Posts: 66
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)

Thu Jun 17, 2021 5:41 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 5:27 pm
"1st, I would never let i be stored in a register (or let cashe it), that's why I use volatile.
I think you misunderstood the point I was trying to make: you should not use volatile, because the compiler will already make sure that `i` is not stored in a register if you use a mutex.
dsyleixa123 wrote: As to your links:
Too many charactres for my simple code example...
I'm afraid I won't be able to explain that to you with fewer characters. If you want an answer to your questions, you should really read those posts, it's all there. Like I said, this is not a simple topic, you have to understand the guarantees made by the language standard, the way your compiler satisfies these guarantees, and what could go wrong when you have a real-world multi-core system with different levels of cache.

For example, consider the following incorrect example:

Code: Select all

std::string message;
bool message_ready = false;

Thread A                    Thread B
--------                    --------

message = "The message";
message_ready = true;

                            while (not message_ready)
                                ; // spin
                            std::cout << message << std::endl;
This code is very bad, because you have no guarantees about the ordering of the different variable accesses. It is very well possible that the code gets reordered to the following (either by the hardware or by the compiler):

Code: Select all

std::string message;
bool message_ready = false;

Thread A                    Thread B
--------                    --------

message_ready = true;
                            while (not message_ready)
                                ; // spin
                            std::cout << message << std::endl;
message = "The message";
This is a disaster, because now thread B sometimes prints an empty string, or worse, a partially written string.

The only way to prevent this is by either using a mutex, or by using atomics with the correct memory order:

Code: Select all

std::string message;
std::atomic<bool> message_ready{ false };

Thread A                    Thread B
--------                    --------

message = "The message";
message_ready.store(true, std::memory_order_release);

                            while (not message_ready.load(std::memory_order_acquire))
                                ; // spin
                            std::cout << message << std::endl;
Because the atomic stores and loads introduce the necessary fences, the incorrect reordering of the previous code block is no longer possible.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 5:44 pm

come on, I think you'd agree that my example is actually dead-simple, don't you?

Code: Select all

#include <stdatomic.h> // needed for ANSI C?
static _Atomic int myval=0;
static _Atomic bool flag=true;
//...
myval=42;
flag=false;
myval|= 7;
so what would be so hard to rework and correct it to syntactically correct code?

But to your 2-thread-examples above: of course I would wrap mutexes round either entire variable accesses (although I must admit that I don't get the actual problems in your architectures, I hardly speak oop-ish).

tttapa
Posts: 66
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)

Thu Jun 17, 2021 5:50 pm

It's not at all clear to me what your example is trying to demonstrate, there aren't even any threads.
although I must admit that I don't get the actual problems in your architectures, I hardly speak oop-ish
What do you mean by “architectures”? The architecture of a multi-core computer?

I have no idea what OOP has to do with any of that, if you really cannot stand `message_ready.store(true, std::memory_order_release)`, feel free to replace it by `atomic_store_explicit(&message_ready, true, memory_order_release)` but I don't think that's any clearer.
Last edited by tttapa on Thu Jun 17, 2021 5:54 pm, edited 1 time in total.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 5:52 pm

no that's why I cut it down to this dead-simple pattern, just for demonstrating the atomic handling (in C, not C++).
The 1st part is just about global declarations,
the 2nd part (and similar ones) may be put into any thread or even into main().
Last edited by dsyleixa123 on Thu Jun 17, 2021 6:12 pm, edited 1 time in total.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 5:56 pm

What do you mean by “architectures”? The architecture of a multi-core computer?
your 2-thread code-architectures/designs in here
viewtopic.php?p=1878794#p1878794
and here:
viewtopic.php?p=1878813#p1878813

about oop I meant the entire C++ syntax,
and about atomic I don't understand anything yet.
Currently I only use simply volatile + mutexes.
Last edited by dsyleixa123 on Thu Jun 17, 2021 6:01 pm, edited 1 time in total.

tttapa
Posts: 66
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)

Thu Jun 17, 2021 6:01 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 5:52 pm
no that's why I cut it down to this dead-simple pattern, just for demonstrating the atomic handling (in C, not C++).
The 1st part is just about global declarations,
the 2nd part (and similar ones) my be put into any thread or even into main().
I'm not sure what you want me to fix about it, once you include the necessary headers and wrap the statements in a function, it compiles just fine:

Code: Select all

#include <stdatomic.h>
#include <stdbool.h>

static _Atomic int myval = 0;
static _Atomic bool flag = true;

int main() {
    myval = 42;
    flag = false;
    myval |= 7;
}
dsyleixa123 wrote:
What do you mean by “architectures”? The architecture of a multi-core computer?
the code-architectures/designs in here: viewtopic.php?p=1878813#p1878813
The problem is that the compiler and the hardware reorder your code. The order that you write statements in your source code does not correspond to the order that the corresponding hardware instructions are executed and that the effects are visible in memory. If you use a single thread, it's invisible to the programmer, once you start programming for multiple threads or even multiple CPUs, this becomes problematic, because you do observe the effect of reorderings and changes to variables take time to propagate through the caches and between CPU cores.
Again, this is all explained in the links I posted earlier.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 6:02 pm

Code: Select all

#include <stdatomic.h>
#include <stdbool.h>

static _Atomic int myval = 0;
static _Atomic bool flag = true;

int main() {
    myval = 42;
    flag = false;
    myval |= 7;
}
did you compile by gcc or g++ ?
is stdatomic.h a C or a C++ lib?

Is "static" absolutely necessary ?

Additionally, in the other thread it was claimed that this line is wrong:

static _Atomic int myval = 0;

tttapa
Posts: 66
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)

Thu Jun 17, 2021 6:17 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 6:02 pm
did you compile by gcc or g++ ?
is stdatomic.h a C or a C++ lib?
GCC, and it's a C header. Where else are you getting `bool`, `true` and `false` when programming in C?
dsyleixa123 wrote: Additionally, in the other thread it was claimed that this is wrong:

static _Atomic int myval = 0;
The other thread might be right. I'm not familiar with the rules for C atomics, thanks to the existence of constructors in C++ you can just initialize them to a value. The documentation for `ÀTOMIC_VAR_INIT` seems to suggest that it was unnecessary in C11 and deprecated in C17: https://en.cppreference.com/w/c/atomic/ATOMIC_VAR_INIT
You could look it up in the C standard if you really care, or just believe the stackoverflow answer from the other thread. Or just use the C++ atomics which are easier to use.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 6:23 pm

what do they mean here? https://en.cppreference.com/w/c/atomic/ATOMIC_VAR_INIT
Does it mean that values cannot be assigned by declaration like for simple standard data types?
perhaps this then:
static _Atomic int myval (0); // ?

or which different syntax for initializing in C17 (AND C11, backwards-compatible)?

But the rest of assignments/syntax in my code are correct, i.e. they can be used just like with simple standard data types?
And then discard all/any additional mutexes completely?

tttapa
Posts: 66
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)

Thu Jun 17, 2021 6:30 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 6:23 pm
what do they mean here? https://en.cppreference.com/w/c/atomic/ATOMIC_VAR_INIT
Does it mean that values cannot be assigned like for simple standard data types?
perhaps this then:
static _Atomic int myval (0); // ?

or which different syntax for initializing in C17 (AND C11, backwards-compatible)?
Like I said, I'm not familiar with atomics in C. If you want a definitive answer, you'll have to look in the standard. Atomics are a topic used by very few experts, and as you've noticed, good documentation is scarce, but the standard should answer this.
dsyleixa123 wrote: But the rest of assignements in my code are correct, i.e. they can be used just like with simple standard data types?
And then discard all/any additional mutexes completely?
Absolutely not. Mutexes and atomics are not the same thing, you cannot simply replace everything with atomics and just remove all mutexes.
Some problems can be solved (in different ways) by mutexes or atomics, but they are not interchangeable, you need to redesign your data structures and algorithms.
To use atomics, you need to know exactly what you're doing.

Again, please read the links I posted earlier.

dsyleixa123
Posts: 1494
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)

Thu Jun 17, 2021 6:33 pm

you'll have to look in the standard.
which standard where?
you cannot simply replace everything with atomics and just remove all mutexes.
of course not everywhere, but mutexes like in your 2-thread examples above, when 1 threads reads whilst another writes arbitrarily.

tttapa
Posts: 66
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)

Thu Jun 17, 2021 6:49 pm

dsyleixa123 wrote:which standard where?
The standard of the programming language you're using. See the isocpp and open-std links here: https://stackoverflow.com/questions/816 ... -documents
dsyleixa123 wrote: of course not everywhere, but mutexes like in your 2-thread examples above, when 1 threads reads whilst another writes arbitrarily.
There are not many examples where it's that simple, but in that case, it might be alright. My advice still holds: don't use atomics before you've seen atomic<> Weapons and the blog posts from earlier.

dsyleixa123
Posts: 1494
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 8:01 am

I don't understand those technical documents and manuals https://stackoverflow.com/questions/816 ... -documents - 99.9999% is exaggerated unspecific and verbose talk in technical terms and terminologies overloaded and overwhelmed with unnecessary and ambiguous data.
I am a hobby user of an Arduino level, I learn from working examples and need exact answers to specific questions, and I'm still not clear about the intializations and other things.

OTOH, if I'll still need atomic+mutexes, then I also can stay with my current volatile+mutexes which is much simpler.

But I'll test your reworked code by some extra modifications (e.g., extra printf() for testing) and hope that the initialization at declaration and all the rest will work.
Thank you so far, I'll report ASAP if I can make it work or not.

PS, as to volatile:
my semaphores e.g. for stopping perpetual threads or other thread-handling purposes may also be triggered by a GPIO button press (digitalRead()) or by a qt5 GUI mouse action (form button press) or by a value read from i2c or UART (e.g., for an emergency stop by environmental events), and that's also a reason why I am using volatile for my semaphores. Will atomic work also for those external device signals just like volatile?

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 29024
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)

Fri Jun 18, 2021 9:01 am

dsyleixa123 wrote:
Fri Jun 18, 2021 8:01 am
I don't understand those technical documents and manuals https://stackoverflow.com/questions/816 ... -documents - 99.9999% is exaggerated unspecific and verbose talk in technical terms and terminologies overloaded and overwhelmed with unnecessary and ambiguous data.
I am a hobby user of an Arduino level, I learn from working examples and need exact answers to specific questions, and I'm still not clear about the intializations and other things.

OTOH, if I'll still need atomic+mutexes, then I also can stay with my current volatile+mutexes which is much simpler.

But I'll test your reworked code by some extra modifications (e.g., extra printf() for testing) and hope that the initialization at declaration and all the rest will work.
Thank you so far, I'll report ASAP if I can make it work or not.

PS, as to volatile:
my semaphores e.g. for stopping perpetual threads or other thread-handling purposes may also be triggered by a GPIO button press (digitalRead()) or by a qt5 GUI mouse action (form button press) or by a value read from i2c or UART (e.g., for an emergency stop by environmental events), and that's also a reason why I am using volatile for my semaphores. Will atomic work also for those external device signals just like volatile?
Please start listening to what the experts are telling you, READ THE LINKS.

If the links are too complicated for you to understand, then you are not going to get anywhere with this. Multithreaded code is NOT EASY. There are NO SHORTCUTS. You HAVE TO UNDERSTAND what the articles being linked to are saying, or you will get it wrong.

The fact you keep saying you don't understand the linked articles, or they are too complicated, is a smoking gun that you have bitten off more than you can chew.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Working in the Application's Team.

Return to “C/C++”