> But can you name the category of such programs
volatile objects are typically used when they are shared between normal program code and:
1. Code in a signal handler
2. An interrupt service routine
3. Memory-mapped i/o devices
etc.
> I don't guess that concurrency/multi-threading is the only one area for that.
Normal multithreaded code is *not* an area for the use of the
volatile qualifier.
> if there's some shared data we still need to consider locks, mutex and condition variable to handle it?
Yes (or use atomic operations). This would be required no matter how the multithreading is realised: with
std::thread,
std::async, native OS threads, whatever...
If a data race occurs, the behaviour of the program is undefined.
https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races
> assert has been used to check an equivalent, but there you apply an *assignment*.
There is a typo in the original code; it should have been an equality comparison instead of an assignment.
assert( result == N * (N+1) / 2 ) ; // sanity check