2009-02-17 14 views
43

Esiste qualcosa come un test-and-set, un semaforo o un blocco atomico in Javascript?semaforo JavaScript/test-and-set/lock?

Ho javascript che richiama processi in background asincroni tramite un protocollo personalizzato (il processo in background viene eseguito letteralmente in un processo separato, non correlato al browser). Credo di essere in una condizione di gara; il processo in background ritorna tra il mio test e il mio set, avvitando le cose sul lato javascript. Ho bisogno di un'operazione test-and-set per renderlo un vero semaforo.

Ecco il codice javascript che tenta di rilevare i processi in background e in coda:

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 è un Singleton che implementa la coda; chiunque voglia invocare un processo esterno chiama Call.call ("qualcosa").

Qualche idea?

+0

È possibile specificare quale sia il "processo" più dettagliato. È questo javascript lato server? –

+2

Il codice Javascript è sempre atomico, quindi non è necessario bloccare o altro. Vedi [Perché non abbiamo uno strumento di controllo della concorrenza in javascript?] (Http://uzairfarooq.github.io/why-no-concurrency-control-tool-in-javascript/). –

risposta

2

Forse si potrebbe implementare un semaforo base intero, basta aggiungere la variabile nel DOM e bloccare/sbloccare e assicurarsi che le funzioni di mantenere il controllo di esso, altro li timeout =)

Se si utilizza un tale quadro come Mootools puoi provare a gestire il flusso dell'app con eventi come onComplete e così via.

18

JavaScript non ha una semantica di blocco perché JS non è un linguaggio con più thread. Più thread possono operare contemporaneamente in contesti completamente distinti, ad es. Thread HTML5 Worker, o in cose come più istanze dell'oggetto contesto JavaScript JavaScript (suppongo che SpiderMonkey abbia un concetto simile). Non possono avere uno stato condiviso, quindi in pratica tutte le esecuzioni sono atomiche.

Va bene, come avete ora fornito alcuno del vostro codice che ho suppone che si abbia qualcosa di simile a:

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

o qualcosa del genere (utilizzando le API appropriate). In tal caso, mi aspetterei che il motore JS blocchi se JS è in esecuzione nel contesto del tuo oggetto js (che è ciò che JavaScriptCore farebbe), in caso contrario sarà probabilmente necessario mettere un blocco manuale attorno all'esecuzione di js.

Che motore stai usando per fare tutto questo? Chiedo perché sulla base della tua descrizione sembra che tu stia impostando una bandiera da un thread secondario da una lingua non JS usando l'API C/C++ fornita da quella lingua, e la maggior parte dei motori JS suppone che qualsiasi manipolazione dello stato fatta tramite l'API si verificherà su un singolo thread, in genere lo stesso thread su cui si verifica l'esecuzione.

+0

Ho aggiunto il codice completo qui sopra per renderlo un po 'più chiaro. Il motore è Webkit (safari). Da javascript invoco i processi esterni, e il processo esterno invoca il metodo "done" quando è fatto. Fondamentalmente ho bisogno di assicurarmi che venga eseguito solo un processo esterno alla volta. – Parand

+0

Supponendo che stai facendo qualcosa di simile a [someObject call] o JSObjectCallAsFunction (context, doneFunction, someObject), dovresti assicurarti di chiamare sul thread principale, specialmente se stai utilizzando l'API JS ObjC fornita da WebKit (IIRC potrebbe aggirare alcune delle serrature) – olliej

+0

Hai mai usato l'sdk webkit sull'iPhone? Sto usando un semplice schema window.location, non ho provato l'SDK. Mi piacerebbe saperne di più sull'SDK. – Parand

0

Ho roba ajax che popola le liste di selezione, avevo bisogno che fosse bloccata così ho fatto qualcosa di simile. Penso che potresti probabilmente farlo più semplice usando i differiti e le pipe o qualcosa del genere.

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

Innanzitutto, se è vero che JavaScript è singolo filettato, non è vero che nessun meccanismo di serializzazione è mai richiesto da un'applicazione JavaScript.

Un semplice esempio è quando un pulsante di invio deve dissolversi per un determinato periodo di tempo durante il quale una richiesta Ajax su un server funziona. Quando la richiesta Ajax asincrona viene completata correttamente, dovrebbe apparire un messaggio dove si trovava il pulsante.

Mentre sarebbe bello poter annullare la dissolvenza del pulsante e semplicemente impostare il suo stile su "Visualizza: nessuno", non appena la richiesta Ajax viene completata, ciò non è possibile in jQuery. Inoltre, una soluzione potrebbe utilizzare Eventi per sincronizzare le due attività simultanee, ma questo è essenzialmente eccessivo per un semplice problema.

Una soluzione low-tech è quello di interrogare un blocco e quando la dissolvenza lo completa è sbloccato, ma il "server fatto" il messaggio non viene visualizzato fino a quando la richiamata successo, come stabilito dal $ .post, esegue.

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 

Infine, credo che questo è la risposta più dettagliata, lungo le linee già suggerito in questa discussione per perrohunter.