Come risolvere il problema del blocco implicito e dell'esecuzione parallela?

3

Dove si trova il codice:

function A()
{
    lock()
    doSomething()
    unlock()
}

Possiamo chiamare A in modo sicuro da più thread, ma non sarà mai eseguito in parallelo. Per l'esecuzione parallela, dobbiamo eludere tutto questo codice.

Ma il problema è che non sappiamo mai che A sta ottenendo il blocco o meno. Se abbiamo codice sorgente (forse un caso fortunato), dobbiamo decodificare tutto il codice per sapere che il blocco sta accadendo o meno. Questo fa schifo. Ma ancora peggio è che normalmente non abbiamo codice sorgente. E il caso del blocco esiste sulla libreria di base?

È ovvio che questo tipo di blocchi nascosti diventerà un collo di bottiglia dell'esecuzione parallela, anche se tutte le altre parti sono progettate per il parallelo.

E inoltre, (1) Con i blocchi, l'esecuzione non può essere parallela. (2) E non posso sapere se i blocchi sono usati o meno in alcun codice. (3) Dire in modo difensivo, non posso rendere parallelo nulla!

Questo fatto mi fa impazzire. Come risolvi questo problema?

    
posta Eonil 29.06.2011 - 10:00
fonte

3 risposte

3

Innanzitutto, A non è bloccato ma piuttosto i thread vengono bloccati alla chiamata di "lock ()". Non c'è nessun meccanismo di blocco nascosto qui. Viene eseguito un semplice controllo che verifica che nessun altro thread stia attualmente bloccando il blocco. Se è bloccato, attende finché non viene sbloccato, altrimenti continua ad eseguire il codice.

Hai ragione che, in generale, il codice di blocco dovrebbe essere evitato a meno che non sia assolutamente necessario e quando si blocca, deve tenere un blocco per il minor tempo possibile per evitare potenziali colli di bottiglia. Una buona regola per sapere quando il codice dovrebbe essere bloccato è porsi le seguenti domande:

  • In qualsiasi fase di questo processo, mi interessa se è stato interrotto? (immagina la mancanza di potenza al computer e non tutto il tuo codice viene eseguito .. sarebbe un problema?)
  • Se il mio programma continuava a rieseguire il codice a causa di qualche errore del processore, a parte le variabili locali, ci sarebbe qualche tipo di rischio di manomissione del risultato finale nell'esecuzione precedente?

Se rispondi sì a entrambi, congratulazioni! Hai trovato il codice che devi bloccare.

In genere esistono due tipi di blocchi: blocchi di lettura e scrittura. Se vedi solo "lock ()" e "unlock ()", quello che vedi è un blocco di scrittura. Un blocco di scrittura è la forma più grave di blocco e blocca i thread indipendentemente da ciò che stai eseguendo. A volte potrebbe non essere nemmeno necessario eseguire un'operazione, basta semplicemente controllare per vedere se è necessario, ma non si desidera leggere i dati che potrebbero essere stati modificati da un altro thread, quindi è necessario tenerlo in un blocco. Per questo, hai bisogno di un blocco di lettura. I blocchi di lettura vengono sempre utilizzati in combinazione con un blocco di scrittura. In genere si vede immediatamente un blocco di lettura e una sorta di controllo. Se il controllo viene superato, si inserisce un blocco di scrittura per assicurarsi che nessun thread possa accedere alla sezione di blocco della lettura finché non si è certi che si trovi in uno stato coerente.

Se lo scrivi correttamente, non devi sapere se un thread è bloccato o meno, proprio come non sai quando scrivere su un file causerà il blocco di un programma mentre viene utilizzato da un altro programma.

Se questo non ha risposto alla tua domanda, allora forse non ho seguito completamente quello che stavi chiedendo.

    
risposta data 29.06.2011 - 12:17
fonte
2

Se chiami A simultaneamente da più thread, succederà una delle tre cose:

1) I thread in realtà non si bloccano a vicenda perché non cercheranno di acquisire il blocco nello stesso momento. In questo caso, continueranno a funzionare contemporaneamente e non ci saranno problemi.

2) I thread entreranno in conflitto sul blocco e uno dei thread non sarà più pronto per essere eseguito. In questo caso, il sistema operativo pianificherà altri thread che non richiedono tale blocco, nel qual caso quei thread continueranno a essere eseguiti contemporaneamente e non ci saranno problemi.

3) Una volta pianificati tutti i thread che non richiedono il blocco, ci sono ancora nuclei inattivi. Solo un thread che richiede il blocco può essere pianificato su quel core. Ma questo succede solo quando tutto devi fare richiesta chiamando quella funzione.

In altre parole, devi solo preoccuparti di ciò nel 5% -10% del tuo codice che è critico dal punto di vista delle prestazioni. E devi conoscere il codice al di fuori comunque, per ovvi motivi.

    
risposta data 16.08.2011 - 20:46
fonte
1

It's obvious this kind of hidden locks will become bottleneck of parallel execution even all the other parts are designed for parallel.

False. Tutto falso.

(1) With locks, execution cannot be parallel.

In una macchina one-core niente è in realtà parallela, i flussi di istruzioni da due o più thread sono intercalati.

Su un computer dual-core, hai esattamente due flussi di istruzioni parallele intercalate per tutti i thread in esecuzione.

I core sono l'unica effettiva esecuzione parallela. I thread sono intercalati.

I thread appaiono da eseguire in parallelo.

(2) And I can't know whether the locks are used or not in any code.

Che cosa?

(3) Defensively, I can't make parallel anything!

False.

    
risposta data 29.06.2011 - 12:12
fonte

Leggi altre domande sui tag