Source: jscore/MutualExclusion.js

(function() {
    // 1. process A arrives
    // 2. process B arrives
    // 3. B returns with results; stores them to this._status
    // 4. A arrives with outdated results; stores them
    // => make sure that earlier runs cannot override later ones

    // 1. process A arrives; timestamp 1
    // 2. process B arrives; timestamp 2
    // 3. process C arrives; timestamp 3
    // ...
    // 4. A returns; ignored
    // 5. B returns; ignored
    // ...
    // => make sure that consecutive scans cannot block results forever

    // 1. process A arrives; timestamp 1
    // 2. process B arrives; timestamp 2
    // 3. process C arrives; timestamp 3
    // ...
    // 3. B returns; 2 > 0; accepted; store 2
    // 4. A returns; 1 < 2; ignored
    // 5. C returns; 3 > 2; accepted; store 3
    // ...
    // => make sure that consecutive scans cannot block results forever

    /**
     * HOW TO USE
     *
     * 1. while still in non-critical section call {@link Help4.jscore.MutualExclusion#start}
     * save the mutual token that you receive from the call
     *
     * 2. before entering critical sections either use
     * - {@link Help4.jscore.MutualExclusion#try}, to only check if you may enter
     * - {@link Help4.jscore.MutualExclusion#access}, to check and enter if possible
     */

    /** Mutual exclusion manager. */
    Help4.jscore.MutualExclusion = class {
        /** @constructor */
        constructor() {
            this._token = 0;
        }

        /** destroy instance */
        destroy() {
            delete this._token;
        }

        /**
         * enter non-critical section; deliver a token
         * @returns {number}
         */
        start() {
            return new Date().getTime();
        }

        /**
         * deliver the token
         * @returns {number}
         */
        get() {
            return this._token;
        }

        /**
         * access critical section; update token
         * @param {number} token
         * @returns {boolean}
         */
        access(token) {
            if (this.try(token)) {
                this._token = token;
                return true;
            }
            return false;
        }

        /**
         * check whether critical section can be entered
         * @param {number} token
         * @returns {boolean}
         */
        try(token) {
            return token >= this._token;
        }
    }
})();