David Laight wrote:
InterlockedExchange(&status, wmm->dwStatus);
That use of InterlockedExchange() is OTT.
Thank you for the clarification.
I've come across http://gcc.gnu.org/wiki/Atomic/GCCMM http://gcc.gnu.org/wiki/Atomic/GCCMM/PracticalUsage and found the official expression for what I've been trying to explain:
I want the MIDI player to use the *relaxed* memory model.
"Relaxed [...] if you are using an atomic variable simply as a value and don't care about the synchronization aspects (ie, you just want to always see a valid value for the variable), then that maps to the relaxed mode. There may be some academic babble about certain provisions, but this is effectively what it boils down to. The relaxed mode is what you use when you don't care about all that memory flushing and just want to see the values of the atomic itself. This is the fastest model, but make sure you don't depend on the values of other shared variables in other threads. This is also what you get when you use the basic atomic STORE and LOAD macros in C."
MCISEQ is designed around an asymmetric N+1 threading model.
- N application threads may issue MCI commands. Critical sections are used to serialize status changes. - 1 player runs. All it cares about is to observe one valid (atomic) value for the variable wmm->dwStatus. It does not need to lock the memory bus or synchronise caches.
If dwStatus indicates a change, let the player act upon it. If the core's cached dwStatus is stale, the player will see the change after another iteration, afer the memory subsystem will have propagated changes.
This morning, I've even had the idea to poll dwStatus less often, i.e. only after sleeping. That way, all notes of a chord that should be played or released simultaneously would be processed together.
After the player loop finishes, the player too uses a critical section like the N app threads to perform the transition from PLAY (or PAUSE) to STOP.
Regards, Jörg höhle