Se utilizzo i blocchi, il mio algoritmo può essere ancora privo di blocchi?


9

Una definizione comune di lock-free è che almeno un processo fa progressi. 1

Se ho una struttura dati semplice come una coda, protetta da un blocco, un processo può sempre fare progressi, poiché un processo può acquisire il blocco, fare ciò che vuole e rilasciarlo.

Quindi soddisfa la definizione di lock-free?


1 Vedi ad esempio M. Herlihy, V. Luchangco e M. Moir. Sincronizzazione senza ostacoli: code a doppia estremità come esempio. In Distributed Computing, 2003. "È privo di blocchi se garantisce solo che alcuni thread facciano sempre progressi".


3
Ho sempre capito "senza blocco" per descrivere una struttura di dati e un insieme di algoritmi che non usano i blocchi, solo un piccolo insieme definito di operazioni di memoria atomica. Ad esempio drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/…
Paul Johnson

Risposte:


16

Questa non è una definizione per lock-free.

Se puoi garantire progressi, allora hai deadlock-free , e se hai l'eventuale completamento di ogni richiesta, allora sei privo di fame , ma non lock-free.

Mi chiedo se il tuo semplice esempio lo fornisca comunque. È necessario disporre di gerarchie di blocchi e così via per garantire effettivamente progressi quando sono coinvolti più blocchi.


1
Sto usando la definizione di M. Herlihy. Una metodologia per l'implementazione di oggetti dati altamente concorrenti. Transazioni sulla programmazione di linguaggi e sistemi, 1993. "La condizione senza blocco garantisce che alcuni processi avanzeranno sempre nonostante interruzioni arbitrarie o ritardi causati da altri processi"
Joe Pension

12
@Joe: Questa non è una definizione, descrive un'implicazione. Attenzione all'errore logico dell'inverso.
Ben Voigt,

2
Potrebbero anche citare M. Herlihy, V. Luchangco e M. Moir. Sincronizzazione senza ostacoli: code a doppia estremità come esempio. In Distributed Computing, 2003. "È privo di blocchi se garantisce solo che alcuni thread facciano sempre progressi".
Joe Pension

1
c'è anche la mancanza di fame che è più specifica di quella senza deadlock (ogni processo può andare avanti qualunque cosa facciano altri processi) notare che i loop di CaS (basati su primitivi atomici) non lo sono
maniaco del cricchetto

5
@Joe: Se il resto del mondo chiama quella proprietà senza deadlock , allora userò quel termine. No, il tuo semplice esempio non è privo di deadlock. Per garantire che qualcosa sia privo di deadlock, non è solo necessaria la sincronizzazione, ma una garanzia che nessun thread esegua alcuna operazione di blocco mentre si tiene il blocco. "fare ciò che vuole" è estremamente vago e non sembra fornire questa garanzia.
Ben Voigt,

11

Ho studiato The Art of Multiprocessor Programming 1 e il loro testo manca di chiarezza, proprio come il libro a cui ti riferisci. Ecco alcune citazioni da TAMPP:

Citazione 1 (definizione di senza blocco)

Un metodo è senza blocco se garantisce che infinitamente spesso una chiamata al metodo termina in un numero finito di passaggi.

Citazione 2 (Definizione di non blocco)

una chiamata in sospeso di un metodo totale non è mai richiesta per attendere il completamento di un'altra chiamata in sospeso.

Preventivo 3 (affermare che il blocco non è bloccabile)

Le condizioni di avanzamento senza blocco e senza blocco e attesa garantiscono che il calcolo nel suo insieme proceda, indipendentemente da come il sistema pianifica i thread.

Il problema è che l'affermazione della citazione 3 non segue ovviamente la definizione della citazione 1. Come già accennato, una coda sincronizzata sembra soddisfare la citazione 1: infinitamente spesso alcuni metodi acquisiscono correttamente il blocco e completano.

Nota in particolare la frase piuttosto vaga nella citazione 3: "indipendentemente da come il sistema pianifica i thread". Questo non è preceduto da alcun tipo di descrizione formale del "sistema di schedulazione dei thread", quindi siamo lasciati a ricostruire le sue proprietà in base ai nostri preconcetti su cosa dovrebbero significare le definizioni :

  1. il sistema esegue sempre le istruzioni di alcuni thread;
  2. non può mai eseguire le istruzioni di un dato thread;
  3. tutti i thread invocano il metodo in esame.

Su un tale sistema, un metodo di blocco non può essere privo di blocco: se il thread che tiene il blocco non è mai più programmato per l'esecuzione, non ci sarà nessun altro thread in grado di completare la sua chiamata al metodo in un numero finito di passaggi, ma ci sarà alcuni thread che stanno eseguendo i passaggi del metodo. Per un sistema più realistico, che garantisca alla fine il tempo di CPU per ciascun thread, la definizione deve includere esplicitamente la proprietà non-blocking:

Definizione corretta di lock-free

Un metodo è senza blocco se non è bloccante e, inoltre, garantisce che infinitamente spesso una chiamata al metodo termina in un numero finito di passaggi.

1 Maurice Herlihy, Nir Shavit, The Art of Multiprocessor Programming, Elsevier 2008, pagg. 58-60


1
La formulazione della citazione 1 è davvero strana. Cosa significano per "infinitamente spesso"? Ovviamente qualcosa di diverso da "sempre", quindi va bene che il metodo non ritorni mai in "alcuni" casi?
Hulk,

Sì, il linguaggio impreciso abbonda. Che cosa è "spesso" comunque? Penso che significhino "in una storia di esecuzione infinita, questo particolare evento si verifica infinitamente molte volte".
Marko Topolnik il

5

La terminologia non è sempre coerente, ma penso che sia importante porre le seguenti domande su un algoritmo o sistema proposto:

  1. Esiste una sequenza di eventi in cui i thread potrebbero rimanere bloccati in attesa l'uno dell'altro anche se a tutti i thread fosse concesso tutto il tempo della CPU che potrebbero usare [in tal caso, non è privo di deadlock]
  2. Se un thread fosse bloccato per un tempo arbitrario a lungo, ciò potrebbe bloccare altri thread o compromettere il funzionamento del sistema per un tempo arbitrariamente lungo [in tal caso, non è non bloccante].
  3. Esiste una combinazione almeno teoricamente possibile della pianificazione dei thread che potrebbe causare a tutti i thread di riprovare ripetutamente le stesse operazioni mentre invalidano il lavoro a vicenda, senza che nessuno faccia progressi [in tal caso, non è privo di blocchi]
  4. Se ad alcuni thread viene concesso un tempo CPU sufficiente rispetto ad un altro, potrebbero forzare quest'ultimo thread a riprovare indefinitamente le sue operazioni [in tal caso, non è senza attesa].

Gran parte del significato degli algoritmi senza blocco non è che sono più veloci degli algoritmi senza blocco, ma piuttosto il fatto che non sono inclini a morire se un thread viene smarrito [si noti che tale garanzia richiede semplicemente che gli algoritmi non sono bloccanti, ma tutti gli algoritmi senza blocco sono]. È possibile che un algoritmo senza blocco utilizzi i blocchi, ma solo se i tentativi di acquisizione dei blocchi includono timeout insieme agli algoritmi per garantire che sia sempre possibile per qualcuno fare progressi (ad esempio, un algoritmo potrebbe utilizzare un CompareExchangeciclo come principale metodo di arbitrato, ma usa i blocchi per arbitrare l'accesso quando la contesa sembra elevata; se un blocco sembra essere trattenuto per un tempo eccessivamente lungo, altri thread potrebbero decidere di abbandonare gli sforzi per utilizzare quel blocco e invece crearne uno nuovo.CompareExchange, avere clienti che abbandonano il blocco non comprometterebbe la coerenza del sistema, anche se ciò potrebbe significare che il codice che aveva il vecchio blocco non farà alcun lavoro fino a quando non abbandona anche il vecchio blocco e si mette in linea con quello nuovo.


Questo è diverso dalla terminologia standard: 2. si riferisce al significato standard di non-blocco mentre 3. si riferisce alla libertà di blocco.
Marko Topolnik,

Ho visto usi terminologici incoerenti e non conosco uno standard "ufficiale". La cosa più importante è che esistono diverse garanzie che un algoritmo può essere in grado di offrire ed è importante utilizzare un algoritmo che offra garanzie sufficienti a soddisfare i requisiti dell'applicazione. Molti documenti coprono solo alcune delle garanzie di cui sopra, ma ci sono casi in cui ciascuno potrebbe essere in grado di soddisfare i requisiti dell'applicazione più facilmente di qualsiasi altra garanzia che soddisferebbe i requisiti.
supercat

Penso che ci sia consenso sul fatto che la terminologia presentata in The Art of Multiprocessor Programming sia "standard".
Marko Topolnik,

@MarkoTopolnik: allora modificherò il post per adattarlo. Ti piace la nuova versione?
supercat

Bello, molto carino.
Marko Topolnik,

4

Devi guardare la "definizione" che citi nel contesto :

Il modo tradizionale di implementare strutture di dati condivise è utilizzare l'esclusione reciproca (blocchi) per garantire che le operazioni simultanee non interferiscano l'una con l'altra. Il blocco presenta una serie di svantaggi rispetto all'ingegneria del software, alla tolleranza agli errori e alla scalabilità (vedere [8]). In risposta, i ricercatori hanno studiato una varietà di tecniche di sincronizzazione alternative che non impiegano l'esclusione reciproca . Una tecnica di sincronizzazione è senza attesa se assicura che ogni thread continuerà a fare progressi di fronte a ritardi arbitrari (o persino errori) di altri thread. È senza blocco se garantisce solo che alcuni thread facciano sempre progressi.

Stai usando i lucchetti per l'esclusione reciproca, quindi non è una tecnica priva di lucchetto di cui stanno parlando.


2

Se utilizzo i blocchi, il mio algoritmo può essere ancora privo di blocchi?

Potrebbe essere, ma dipende dall'algoritmo.

Se ho una struttura dati semplice come una coda, protetta da un blocco, un processo può sempre fare progressi, poiché un processo può acquisire il blocco, fare ciò che vuole e rilasciarlo.

Quindi soddisfa la definizione di lock-free?

Nota di per sé .

Se il passaggio "fai quello che vuole" non comporta l'acquisizione di altri blocchi, ed è garantito il completamento in un tempo finito, questa particolare parte del tuo algoritmo sarà libera da deadlock.

Tuttavia, se tali presupposti non sono soddisfatti, esiste almeno il potenziale di deadlock ...


Dopo aver studiato il testo in The Art of Multiprocessor Programming, sono giunto alla conclusione che i mutex invalidano definitivamente la definizione di lock-free, quando la definizione è spiegata correttamente. Ho aggiunto una risposta a questa pagina per chiarire questo.
Marko Topolnik,

1

L'esempio fornito non è privo di blocchi per il seguente motivo.

Supportare un thread acquisisce il blocco e lo scheduler del sistema operativo ha sospeso il thread per un periodo di solitario infinito, quindi tutto il thread non può fare progressi poiché non è possibile acquisire il blocco acquisito dal thread sospeso.

In generale, gli algoritmi che utilizzano i blocchi non sono senza blocco.

Si noti che deadlock-free e lock-free sono due concetti diversi. senza deadlock significa che non c'è possibilità di deadlock, ma potrebbe esserci un livelock che può impedire a tutto il sistema di progredire. La libertà di blocco è più forte di quella perché significa che alcuni thread nel sistema fanno sempre progressi con un numero finito di passaggi.


Guarda una definizione più attenta su Wikipedia: "Un algoritmo è privo di blocchi se soddisfa che quando i thread del programma sono eseguiti sufficientemente a lungo almeno uno dei thread fa progressi." Ciò esclude il caso di arresto dei thread. Anche i progressi sotto l'arresto sono coperti dalla libertà di ostruzione , non dalla libertà di blocco .
Marko Topolnik,

@MarkoTopolnik Il tuo commento non ha alcun senso. La libertà di blocco copre la libertà di ostruzione. Tutto ciò che è privo di blocco deve essere privo di ostruzioni. E la definizione che hai dato non esclude l'arresto dei thread.
Chaoran,

Si prega di fare attenzione a distinguere "senso" da "essere corretto". Il mio commento è errato, come si può vedere dalla mia risposta successiva. Ma la definizione di Wikipedia è anche sbagliata o almeno ambigua.
Marko Topolnik,

@MarkoTopolnik Dato che ammetti che il tuo commento non è corretto, dovresti rimuoverlo per evitare di confondere gli altri lettori. Wikipedia è spesso errata o ambigua. Dovresti trovare definizioni sottili come "lock-freedom" in documenti accademici come cs.rochester.edu/~scott/papers/2006_PPoPP_synch_queues.pdf (la definizione di lock-free è nella sezione 2.1)
Chaoran

Sì, includere la proprietà non bloccante come parte della definizione di libertà di blocco è un modo per farlo. Ciò è stato affermato in una precedente revisione della mia risposta.
Marko Topolnik,
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.