2009-05-23 10 views
5

Qualcuno potrebbe spiegare la sincronizzazione delle condizioni con me?Che cos'è la sincronizzazione delle condizioni?

Un esempio (preferibilmente in C#) sarebbe molto apprezzato anche.

+1

Ho sentito parlare di "sincronizzazione": di solito è una frase relativa al multi-threading, in particolare con vari tipi di "lock" che possono essere richiesti per "sincronizzare" i thread per rendere il codice "thread-safe" ". Ma non so, in particolare, "* condizione * sincronizzazione". – ChrisW

risposta

8

Sembra che il tuo professore sta parlando di threading. La filettatura consente ai programmi per computer di fare più di una cosa alla volta. L'atto di iniziare un nuovo thread mentre uno è già in esecuzione è chiamato "rotazione di un thread" da parte dei programmatori di computer.

I thread possono condividere lo stesso spazio di memoria. Condition Synchronization (o semplicemente sincronizzazione) è un meccanismo che protegge le aree della memoria da essere modificato da due thread diversi allo stesso tempo.

Diciamo che sei fuori a fare shopping, e la moglie è a casa a pagare le bollette. Questo è un esempio ingenuo, e non funziona davvero in questo modo nella vita reale, ma servirà da semplice illustrazione.

Tua moglie paga una fattura online. Allo stesso tempo, stai facendo scorrere la tua carta di credito al supermercato. Entrambi gli atti comportano lo spostamento di denaro dal tuo conto corrente. Per simulare questa attività, scriviamo il seguente codice:

public class MyBanking 
{ 
    static double myAccountBalance; 
    // 
    public void DebitAccount(double debitAmount) 
    { 
     Console.Writeline("Your Old Balance is: " + myAccountBalance.ToString()); 
     Console.Writeline("Your Debit is:  " + debitAmount.ToString()); 
     myAccountBalance = myAccountBalance - amount; 
     Console.Writeline("Your New Balance is: " + myAccountBalance.ToString()); 
    } 
} 

Ipoteticamente, tua moglie è in esecuzione una sola istanza ("copia") di questa classe su un filo, si esegue un'istanza su un altro thread. La variabile myAccountBalance è dichiarata statica per consentirne la condivisione tra entrambe le istanze in esecuzione (tu e tua moglie avete un solo account di controllo).

Fate il vostro debito chiamando il codice come questo:

MyBanking bankingObject = new MyBanking(); 
bankingObject.DebitAccount(100); 

Tua moglie fa il suo debito al tempo stesso:

MyBanking bankingObject = new MyBanking(); 
bankingObject.DebitAccount(50); 

Che cosa succede se il tuo thread viene interrotto dal filo di tua moglie dopo che il vecchio saldo è stato stampato sullo schermo, ma prima che venga stampato il nuovo saldo? Il thread di tua moglie addebita l'account e restituisce il controllo al thread.Tua moglie vede questo sullo schermo:

Your Old Balance is: 2000 
Your Debit is:  50 
Your New Balance Is: 1950 

Quando il computer stampa il nuovo equilibrio sul vostro schermo, sarà sbagliato, perché di debito di tua moglie sarà stato contato anche. Verrà visualizzato qualcosa del tipo:

Your Old Balance is: 2000 
Your Debit is:  100 
Your New Balance Is: 1850 

Per risolvere questo problema, circondiamo il nostro codice metodo con un'istruzione di blocco. L'istruzione di blocco fa in modo che tutti gli altri thread attenderanno il termine dell'istanza. Il nuovo codice è simile al seguente: discussione

public class MyBanking 
{ 
    static double myAccountBalance; 
    // 
    public void DebitAccount(double debitAmount) 
    { 
     lock (this) 
     { 
      Console.Writeline("Your Old Balance is: " + myAccountBalance.ToString()); 
      Console.Writeline("Your Debit is:  " + debitAmount.ToString()); 
      myAccountBalance = myAccountBalance - amount; 
      Console.Writeline("Your New Balance is: " + myAccountBalance.ToString()); 
     } 
    } 
} 

tua moglie sarà ora attendere il vostro codice all'interno l'istruzione lock per terminare l'esecuzione, prima che il codice di tua moglie inizia l'esecuzione. Il tuo nuovo saldo ora sarà corretto, perché non c'è più la possibilità che il thread di tua moglie cambi il saldo mentre completi la TUA transazione. Sullo schermo, ora vedrete questo:

Your Old Balance is: 2000 
Your Debit is:  100 
Your New Balance Is: 1900 

Tua moglie vedrà questo:

Your Old Balance is: 1900 
Your Debit is:  50 
Your New Balance Is: 1850 

Questa è la sincronizzazione.

+0

C'è anche qualcosa chiamato una variabile condizionale. Vedi questo articolo per i dettagli: http://en.wikipedia.org/wiki/Monitor_%28synchronization%29 –

+0

La moglie ha un output sbagliato. 1900 - 50! = 1800 –

+0

@IgorGorjanc: Grazie. –

2

In sostanza si tratta di un modello di progettazione per le discussioni che hanno bisogno

a) sincronizzare l'accesso a una risorsa

b) a volte aspettare che altri thread fino a un certo condizioni è soddisfatta

vi chiedo questo in un Contesto C#, .NET fornisce supporto per questo con Monitor.Wait e Monitor.Pulse (e con i wrapper attorno a vari oggetti Win32 come WaitEventhandle).

Ecco un bello queue example su SO.

i principali dati tecnici assomigliano:

lock(buffer) // is Monitor.Enter(buffer) ... finally Monitor.Leave(buffer) 
{ 
    while (buffer.Count < 1) 
    { 
     Monitor.Wait(buffer); 
    } 
    ... 
} 

Si noti come c'è un'attesa-mentre-bloccato in là. Sembra un deadlock ma Wait rilascia il blocco mentre è in attesa. Il codice all'interno di lock() { } ha ancora accesso esclusivo al buffer quando viene eseguito.

E poi un altro thread è per segnalare quando si mette qualcosa nel buffer:

Monitor.Pulse(buffer); 
1

Il codice sopra riportato è quasi corretto ma in realtà non è corretto. Utilizzando lock(this), bloccherai solo l'istanza della classe MyBanking, ma tua moglie bloccherà la sua. Per bloccare l'accesso alla variabile condivisa è possibile bloccare il tipo (ad esempio lock(typeof(MyBanking))) oppure è possibile introdurre una nuova variabile condivisa e bloccare che (non è possibile bloccare un int così tipicamente persone creare un oggetto come segue.

class MyBanking 
{ 
    static object lockObj = new object(); 
    static double myAccountBalance; 
    public void DebitAccount(double debitAmount) 
    { 
     lock (lockObj) 
1

sincronizzazione è stato chiaramente spiegato già. Tuttavia, sincronizzazione condizione impone specificamente che un processo/thread esegue solo dopo una condizione è verificata. Tipicamente, la condizione sarà che qualche altro processo/thread è già eseguito.

Nell'esempio fornito di addebito di un account e visualizzazione del saldo. Se la visualizzazione del saldo era un metodo sincronizzato separato e volevamo visualizzare il saldo solo dopo che il tuo account era stato addebitato, ciò richiederebbe la sincronizzazione delle condizioni.

La sincronizzazione delle condizioni è molto ben descritta dal producer-consumer problem.

Problemi correlati