web-dev-qa-db-fra.com

Sémaphore Javascript/test-and-set/lock?

Existe-t-il un ensemble de tests atomiques, de sémaphores ou de verrous Javascript?

Javascript appelle des processus d'arrière-plan asynchrones via un protocole personnalisé (le processus d'arrière-plan s'exécute littéralement dans un processus distinct, indépendant du navigateur). Je crois que je cours dans une condition de course; le processus d'arrière-plan revient entre mon test et mon set, en bousillant du côté javascript. J'ai besoin d'une opération de test pour en faire un véritable sémaphore. 

Voici le code javascript qui tente de détecter les processus en arrière-plan et de les mettre en file d'attente:

Call = function () {

var isRunning = true,
    queue = [];

return  {
    // myPublicProperty: "something",

    call: function (method) {
            if (isRunning) {
                console.log("Busy, pushing " + method);
                queue.Push(method);
            } else {
                isRunning = true;
                objccall(method);
            }
        },

        done: function() {
            isRunning = false;
            if (queue.length > 0) {
                Call.call(queue.shift());
            }
        }
    };
}();

Call est un singleton qui implémente la mise en file d'attente; toute personne souhaitant invoquer un processus externe appelle Call.call ("quelque chose").

Des idées?

45
Parand

JavaScript n'a pas de sémantique de verrouillage car JS n'est pas un langage multithread. Plusieurs threads ne peuvent fonctionner simultanément que dans des contextes complètement distincts - par exemple. Tâches HTML5 Worker, ou dans des choses comme plusieurs instances de l'objet contextuel de l'API JavaScriptCore (je suppose que SpiderMonkey a un concept similaire). Ils ne peuvent pas avoir un état partagé, de sorte que toute exécution est essentiellement atomique.

Ok, comme vous avez fourni une partie de votre code, je suppose que vous avez quelque chose qui ressemble à:

External Process:
<JSObject>.isRunning = true;
doSomething()
<JSObject>.done()

Ou certains tels (en utilisant des API appropriées). Dans ce cas, je m'attendrais à ce que le moteur JS se bloque si JS s'exécute dans le contexte de votre objet Js (ce que ferait JavaScriptCore), faute de quoi vous devrez probablement verrouiller manuellement l'exécution de js.

Quel moteur utilisez-vous pour faire tout cela? Je vous pose cette question car, selon votre description, il semble que vous définissiez un indicateur à partir d'un thread secondaire à partir d'un langage autre que JS à l'aide de l'API C/C++ fournie par ce langage, et la plupart des moteurs JS supposent que toute manipulation d'état effectuée via l'API se produira sur un seul thread, généralement le même thread sur lequel toutes les exécutions ont lieu.

19
olliej

Peut-être que vous pourriez implémenter un sémaphore entier de base, ajoutez simplement la variable dans le DOM et verrouillez-le/déverrouillez-le et assurez-vous que vos fonctions le vérifient, sinon timeout them =) 

Si vous utilisez un cadre tel que Mootools, vous pouvez essayer de gérer le flux de l'application avec des événements tels que onComplete, etc.

2
perrohunter

Tout d’abord, s’il est vrai que javaScript est à thread unique, il n’est PAS vrai qu’aucun mécanisme de sérialisation n’est jamais requis par une application javaScript.

Un exemple simple est lorsqu'un bouton d'envoi doit disparaître pendant une durée définie pendant laquelle une requête Ajax sur un serveur fonctionne. Lorsque la demande Ajax asynchrone se termine avec succès, un message devrait apparaître à l'emplacement du bouton.

Bien qu'il soit agréable de pouvoir annuler le fondu du bouton et simplement définir son style sur "display: none", dès que la requête Ajax est terminée, cela n'est pas possible dans jQuery. En outre, une solution pourrait utiliser Events pour synchroniser les deux activités simultanées, mais il s’agit essentiellement d’une tâche excessive pour un problème simple.

Une solution peu technique consiste à interroger un verrou et, une fois le fade-out terminé, il est déverrouillé, mais le message "serveur terminé" n'est PAS affiché jusqu'à l'exécution du rappel de réussite défini par $ .post.

var gl_lock;
var gl_selfID;

function poll_lock(message) {
     if (gl_lock === 0) {
          $('#output').text(message).fadeIn(200);
          window.clearInterval(gl_selfID);
     }
 } // end of poll_lock

 function worker() {

     // no one gets in or out
     gl_lock = 1;

     $.post(..., data,function() { 
           gl_selfID = window.setInterval(poll_lock, 40, data.message);
      }, "json");

     // end of fadeout unlock the semaphore
     $('#submit-button').fadeOut(400, function() { gl_lock = 0; });

  } // end of worker

Enfin, je pense que cette réponse est plus détaillée et va dans le sens des suggestions précédentes de perrohunter.

1
JackCColeman

Je ne sais pas trop quelle est exactement la question, mais consultez mon objet sémaphore ici: https://github.com/agamemnus/semaphore.js .

0
Agamemnus

J'ai des trucs ajax qui remplissent des listes de sélection, j'avais besoin que ça soit verrouillé alors j'ai fait quelque chose comme ça. Je pense que vous pourriez probablement faire les choses plus simplement en utilisant des différés et des tuyaux ou quelque chose. 

var semaphore=[];

function myFunc(arg){
   var dfd;
   $.when(semaphore[table]).done(
      function(){
            dfd=myFuncInner(arg);
      }
      );
return dfd;
}

function myFuncInner(table){
semaphore[arg] = new $.Deferred();
... 
somethingasynchronous({
    semaphore[arg].resolve();
});

return  semaphore[arg];
}
0
Mark Lester