News for hackers. Stuff that matters.
Re:Implementing a lightweight task scheduler in C++ by danieltillett on Saturday August 22, 2015 @07:27PM (#10104187)
Do you know which platforms or compilers /volatile won't work?
Re:Implementing a lightweight task scheduler in C++ by vvanders on Saturday August 22, 2015 @07:50PM (#10104245)
Volatile works correctly on all platforms.

Don't use it as a synchronization primitive, that's not what it's meant to do. You only should use it:

a. If you're reading from HW.

b. If you want to use it like a const marker for member functions.

Re:Implementing a lightweight task scheduler in C++ by ridiculous_fish on Saturday August 22, 2015 @09:18PM (#10104423)
Here are some other places where volatile is appropriate:

1. Reading or writing shared memory

2. Values which may be modified in signal handlers

3. Implementing atomic types (e.g. boost::atomic)

4. RCU (e.g. ACCESS_ONCE in Linux kernel)

Re:Implementing a lightweight task scheduler in C++ by vvanders on Saturday August 22, 2015 @09:31PM (#10104443)
Pretty sure the lack of ordering(memory and execution) semantics for volatile invalidates all of those cases.

Really you should be using the appropriate platform memory and execution barriers in place of volatile 99% of the time.

Re:Implementing a lightweight task scheduler in C++ by ridiculous_fish on Sunday August 23, 2015 @12:03AM (#10104642)
Barriers are for ordering as you say, which is important, but orthogonal to volatile. Volatile is about enforcing that a particular access occurs.

An illustration:

    static volatile sig_atomic_t interrupted = 0;
    void sigint_handler(int s) { interrupted = 1; }

    void run()
    {
        signal(SIGINT, sigint_handler);
        for (;;)
        {
           if (interrupted) break;
           stuff();
        }
    }
"volatile" is the most precise way to prevent the compiler from hoisting the 'interrupted' access out of the loop. Memory barriers aren't necessary, because the code is single threaded. They may effectively defeat the optimization too, but it's by confusing the compiler instead of informing it.

edit: Oh, and std::atomic is a very bad solution to the above. std::atomic may take locks, which can lead to a deadlock if used in a signal handler!

Re:Implementing a lightweight task scheduler in C++ by monocasa on Sunday August 23, 2015 @10:38AM (#10105599)
The way I think of it is that volatile is for making sure the instructions are there and in the right order in the instruction stream. You may need to do other things to get around the processor's side of optimizations like store queues and caches depending on the context.
Re:Implementing a lightweight task scheduler in C++ by dougbinks on Sunday August 23, 2015 @04:37AM (#10105033)
Thanks for responding here - this is correct. In the case of implementing atomic types (the use case for enkiTS) volatile is a prerequisite but not on its own sufficient - hence I use atomic intrinsics and memory barriers where appropriate. The repository on github notes that I've only implemented these for Windows, Linux and OSX on Intel x86 / x64, but a C++11 branch exists for those who want.
Re:Implementing a lightweight task scheduler in C++ by rdtsc on Saturday August 22, 2015 @09:47PM (#10104468)
> Reading or writing shared memory

Yeah I was bit by that when writing a shared memory low latency library. When compiled under debug it worked, in release mode values were not being written to the shared memory area. Added some "volatile"-s in there and it worked.

Re:Implementing a lightweight task scheduler in C++ by mrpippy on Sunday August 23, 2015 @02:16AM (#10104829)
And to be exceedingly pedantic, a signal handler should only modify a 'volatile sig_atomic_t' variable. I assume this is just typedef'd to a machine word on all typical POSIX platforms though.
Re:Implementing a lightweight task scheduler in C++ by MaulingMonkey on Saturday August 22, 2015 @08:02PM (#10104266)
/volatile the flag is only supported by MSVC as far as I'm aware.

volatile the keyword was not written with the intent of being a memory barrier (edit: or atomicity for that matter) in mind.

In practice, I've created unit tests to catch and fix issues on mobile (specifically iOS - ARM arch, under both GCC and later Clang compilers IIRC) with our "lock free" circular buffer.

It was indeed lock free. And also just plain broken in multi-core scenarios.