Most Powerful Open Source ERP

How To Prevent Concurrency Execution With A Mutex

  • Last Update:2020-05-14
  • Version:001
  • Language:en

In order to prevent concurrent access to some resources, the renderJS methods can be protected by a mutex.
A protected method is executed only when the previous call is resolved/rejected.

One mutex can also be uses to protect the different methods.

To use a mutex, pass an optional "mutex" parameter to the declareMethod like:

.declareMethod("methodName", function () {...}, {mutex: "mutex_name"})

Here is a full example:

Create one child gadget

HTML

<html>
  <head>
    <script src="rsvp.js"></script>
    <script src="renderjs.js"></script>
    <script src="howto_mutex_child.js"></script>
  </head>
  <body>
  </body>
</html>

JS

(function (rJS, RSVP, window) {
  "use strict";

  function resetCounter() {
    this.counter = 0;
  }

  function increaseCounterAndWaitAndReturn() {
    var gadget = this;
    gadget.counter += 1;
    return new RSVP.Queue(RSVP.delay(50))
      .push(function () {
        return gadget.counter;
      });
  }

  rJS(window)
    .ready(resetCounter)
    .declareMethod("executeNotProtectedMethod", increaseCounterAndWaitAndReturn)
    .declareMethod("executeFirstNonConcurrentMethod", increaseCounterAndWaitAndReturn, {mutex: "first_mutex"})
    .declareMethod("executeSecondNonConcurrentMethod", increaseCounterAndWaitAndReturn, {mutex: "first_mutex"})
    .declareMethod("resetCounter", resetCounter);
}(rJS, RSVP, window));

Create the parent gadget

HTML

<html>
  <head>
    <script src="rsvp.js"></script>
    <script src="renderjs.js"></script>
    <script src="howto_mutex_parent.js"></script>
  </head>
  <body>
    <pre></pre>
  </body>
</html>

JS

(function (rJS, RSVP, window) {
  "use strict";

  function log(gadget, text, expected_value, value) {
    gadget.element.querySelector("pre").textContent += text + " - expected: " + expected_value + " got: " + value + "\n";
  }

  rJS(window)
    .declareService(function () {
      var parent_gadget = this,
        child_gadget;
      return parent_gadget.declareGadget("howto_mutex_child.html", {scope: "child_scope"})
        .push(function (result) {
          child_gadget = result;

          // If not protected with a mutex, method are executed concurrently
          return RSVP.all([
            child_gadget.executeNotProtectedMethod(),
            child_gadget.executeNotProtectedMethod()
          ]);
        })
        .push(function (result_list) {
          log(parent_gadget, "First executeNotProtectedMethod", 2, result_list[0]);
          log(parent_gadget, "Second executeNotProtectedMethod", 2, result_list[1]);

          // One method is protected by a mutex
          return RSVP.all([
            child_gadget.resetCounter(),
            child_gadget.executeFirstNonConcurrentMethod(),
            child_gadget.executeFirstNonConcurrentMethod()
          ]);
        })
        .push(function (result_list) {
          log(parent_gadget, "First executeFirstNonConcurrentMethod", 1, result_list[1]);
          log(parent_gadget, "Second executeFirstNonConcurrentMethod", 2, result_list[2]);

          // Two different methods can use the same mutex
          return RSVP.all([
            child_gadget.resetCounter(),
            child_gadget.executeFirstNonConcurrentMethod(),
            child_gadget.executeSecondNonConcurrentMethod()
          ]);
        })
        .push(function (result_list) {
          log(parent_gadget, "First executeFirstNonConcurrentMethod", 1, result_list[1]);
          log(parent_gadget, "Second executeSecondNonConcurrentMethod", 2, result_list[2]);
        });
    });
}(rJS, RSVP, window));