I mutex sono necessari in javascript?


104

Ho visto questo collegamento: Implementing Mutual Exclusion in JavaScript . D'altra parte, ho letto che non ci sono thread in javascript, ma cosa significa esattamente?

Quando si verificano eventi, dove possono interrompersi nel codice?

E se non ci sono thread in JS, devo usare i mutex in JS o no?

In particolare, mi chiedo circa gli effetti dell'utilizzo di funzioni chiamate da setTimeout()e XmlHttpRequest'l onreadystatechangesu variabili globalmente accessibili.


1
No, nessun mutex o qualsiasi altro strumento di controllo della concorrenza in javascript. Vedi Perché nessuno strumento di controllo della concorrenza in javascript .
Uzair Farooq

Risposte:


101

Javascript è definito come un linguaggio rientrante , il che significa che non ci sono thread esposti all'utente, potrebbero esserci thread nell'implementazione. Funzioni come setTimeout()e i callback asincroni devono attendere che il motore di script si fermi prima di poter essere eseguiti.

Ciò significa che tutto ciò che accade in un evento deve essere completato prima che l'evento successivo venga elaborato.

Detto questo, potresti aver bisogno di un mutex se il tuo codice fa qualcosa in cui si aspetta che un valore non cambi tra quando è stato attivato l'evento asincrono e quando è stato chiamato il callback.

Ad esempio, se hai una struttura dati in cui fai clic su un pulsante e invia un XmlHttpRequest che chiama un callback, la struttura dei dati cambia in modo distruttivo, e hai un altro pulsante che cambia direttamente la stessa struttura dati, tra il momento in cui l'evento è stato attivato e quando è stata eseguita la richiamata, l'utente avrebbe potuto fare clic e aggiornare la struttura dei dati prima della richiamata, che potrebbe quindi perdere il valore.

Sebbene tu possa creare una condizione di gara del genere, è molto facile impedirlo nel tuo codice poiché ogni funzione sarà atomica. Sarebbe molto lavoro e occorrerebbero alcuni strani schemi di codifica per creare la condizione di gara in effetti.


14
Non è affatto difficile creare questa race condition: ad esempio, ho un evento "onkeyup" in un campo, che innesca una chiamata ajax a un DB per ottenere alcuni valori. La digitazione rapida dei dati può facilmente portare a risultati fuori ordine.
thomasb

19

Le risposte a questa domanda sono un po 'datate ma corrette al momento in cui sono state fornite. E ancora corretto se si guarda un'applicazione javascript lato client che NON utilizza webworker.

Articoli sui
webworker : multithreading in javascript utilizzando i webworker
Mozilla sui webworker

Questo mostra chiaramente che javascript tramite web-worker ha capacità di multithreading. Per quanto riguarda la domanda, i mutex sono necessari in javascript? Non sono sicuro di questo. Ma questo post di stackoverflow sembra rilevante:
mutua esclusione per N thread asincroni


3
un tuffo nel passato, ma ho riscontrato la necessità di mutex quando più schede accedono alla stessa memoria locale
psp

3
I WebWorker non influenzano il rientro perché non condividono lo stato della variabile e comunicano solo con il thread principale passando messaggi, che attivano eventi.
Alnitak

9

Come sottolinea @william,

potresti aver bisogno di un mutex se il tuo codice fa qualcosa in cui si aspetta che un valore non cambi tra quando è stato attivato l'evento asincrono e quando è stato chiamato il callback.

Questo può essere ulteriormente generalizzato: se il tuo codice fa qualcosa in cui si aspetta il controllo esclusivo di una risorsa fino alla risoluzione di una richiesta asincrona, potresti aver bisogno di un mutex.

Un semplice esempio è dove hai un pulsante che attiva una chiamata ajax per creare un record nel back-end. Potrebbe essere necessario un po 'di codice per proteggerti dall'attivazione di utenti soddisfatti che fanno clic e quindi creano più record. ci sono un certo numero di approcci a questo problema (ad esempio disabilitare il pulsante, abilitare su ajax successo). Puoi anche usare un semplice lucchetto:

var save_lock = false;
$('#save_button').click(function(){
    if(!save_lock){
        //lock
        save_lock=true;
        $.ajax({
            success:function()
                //unlock
                save_lock = false;  
            }
        });
    }
}

Non sono sicuro che sia l'approccio migliore e sarei interessato a vedere come gli altri gestiscono l'esclusione reciproca in javascript, ma per quanto ne so è un semplice mutex ed è utile.


4
Difficilmente lo chiamerei un mutex, almeno non nel senso tradizionale, perché non hai due thread in esecuzione nel contesto di un singolo blocco in qualsiasi momento.
Ovesh

10
un mutex è semplicemente un algoritmo che aiuta a "evitare l'uso simultaneo di una risorsa comune". Sebbene il multithreading crei la necessità di mutex, non c'è nulla nella definizione che dica che un mutex è specifico per la situazione che descrivi.
alzclarke

1
Hai ragione riguardo alla definizione formale di mutex. Ma questo non è certo ciò a cui le persone pensano quando parlano di mutex nel mondo reale.
Ovesh

Questo non funziona come previsto. Sfortunatamente, i clic ripetuti attiveranno comunque la chiamata ajax. Qualche altra idea?
Mohammed Shareef C

1
Abbastanza sicuro che questo dovrebbe essere racchiuso in un whilecon setTimeouto setIntervalcon clearIntervaldopo n errori in modo da avere una logica di ripetizione e timeout. Lasciando così com'è significa semplicemente bypassare il codice bloccato. La gestione esterna con mutex e oggetti condivisi è importante quanto le implementazioni stesse.
MrMesees

6

JavaScript è a thread singolo ... sebbene Chrome possa essere una nuova bestia (penso che sia anche a thread singolo, ma ogni scheda ha il proprio thread JavaScript ... Non l'ho esaminato in dettaglio, quindi non citarmi Là).

Tuttavia, una cosa di cui devi preoccuparti è come il tuo JavaScript gestirà più richieste ajax che tornano non nello stesso ordine in cui le invii. Quindi, tutto ciò di cui devi veramente preoccuparti è assicurarti che le tue chiamate ajax siano gestite in modo tale che non si calpestino a vicenda se i risultati tornano in un ordine diverso da quello che hai inviato loro.

Questo vale anche per i timeout ...

Quando JavaScript aumenta il multithreading, allora forse preoccuparti dei mutex e simili ...


4

Sì, i mutex possono essere richiesti in Javascript quando si accede a risorse condivise tra schede / finestre, come localStorage .

Ad esempio, se un utente ha due schede aperte, un codice semplice come il seguente non è sicuro:

function appendToList(item) {
    var list = localStorage["myKey"];
    if (list) {
        list += "," + item;
    }
    else {
        list = item;
    }
    localStorage["myKey"] = list;
}

Tra il momento in cui l'elemento localStorage è stato "ottenuto" e "impostato", un'altra scheda potrebbe aver modificato il valore. In genere è improbabile, ma possibile: dovresti giudicare da solo la probabilità e il rischio associati a qualsiasi controversia nelle tue particolari circostanze.

Vedere i seguenti articoli per maggiori dettagli:


2

JavaScript, la lingua , può essere multithreading come desideri, ma gli incorporamenti del browser del motore javascript eseguono solo un callback (onload, onfocus, <script>, ecc ...) alla volta (per scheda, presumibilmente). Il suggerimento di William di utilizzare un Mutex per le modifiche tra la registrazione e la ricezione di una richiamata non dovrebbe essere preso troppo alla lettera per questo motivo, poiché non si vorrebbe bloccare nella richiamata intermedia poiché la richiamata che lo sbloccherà verrà bloccata dietro la richiamata corrente ! (Wow, l'inglese fa schifo per parlare di threading.) In questo caso, probabilmente vorrai fare qualcosa sulla falsariga di ridispacciare l'evento corrente se un flag è impostato, letteralmente o con setTimeout ().

Se stai usando un diverso embedding di JS e che esegue più thread contemporaneamente, può diventare un po 'più rischioso, ma a causa del modo in cui JS può usare i callback così facilmente e blocca gli oggetti sull'accesso alla proprietà il blocco esplicito non è così necessario . Tuttavia, sarei sorpreso se un incorporamento progettato per codice generale (ad esempio, script di giochi) che utilizza il multi threading non fornisse anche alcune primitive di blocco esplicite.

Scusa per il muro di testo!


0

Gli eventi vengono segnalati, ma l'esecuzione di JavaScript è ancora a thread singolo.

La mia comprensione è che quando viene segnalato un evento il motore interrompe ciò che è in esecuzione al momento per eseguire il gestore di eventi. Dopo che il gestore è terminato, viene ripresa l'esecuzione dello script. Se il gestore di eventi ha modificato alcune variabili condivise, il codice ripreso vedrà queste modifiche apparire "di punto in bianco".

Se vuoi "proteggere" i dati condivisi, dovrebbe essere sufficiente un semplice flag booleano.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.