2009-05-23 12 views
5

Est-ce que quelqu'un pourrait expliquer la synchronisation de condition à moi?Qu'est-ce que la synchronisation de condition?

Un exemple (de préférence en C#) serait également très apprécié.

+1

J'ai entendu parler de "synchronisation": il s'agit généralement d'une phrase liée au multi-threading, en particulier avec différents types de "lock" qui peuvent être nécessaires pour "synchroniser" les threads afin de rendre le code thread-safe ". Mais je ne connais pas, en particulier, "* condition * synchronisation". – ChrisW

Répondre

8

Il semble que votre professeur parle threading. Threading permet aux programmes informatiques de faire plus d'une chose à la fois. Le fait de démarrer un nouveau thread alors que l'un d'entre eux est déjà en cours d'exécution est appelé "tourner un fil" par les programmeurs informatiques.

Les threads peuvent partager le même espace mémoire. La synchronisation des conditions (ou simplement la synchronisation) est un mécanisme qui protège les zones de la mémoire d'être modifiées par deux threads différents en même temps. Disons que vous êtes en train de faire du shopping, et que la femme est à la maison pour payer les factures. C'est un exemple naïf, et cela ne fonctionne pas vraiment de cette façon dans la vie réelle, mais cela servira de simple illustration.

Votre femme paie une facture en ligne. En même temps, vous glissez votre carte de crédit à l'épicerie. Les deux actes impliquent de retirer de l'argent de votre compte chèque. Pour simuler cette activité, nous écrivons le code suivant:

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()); 
    } 
} 

Hypothétiquement, votre femme est en cours d'exécution d'une instance (« copie ») de cette classe sur un fil, vous exécutez une instance sur un autre thread. La variable myAccountBalance est déclarée statique pour permettre son partage entre les deux instances en cours d'exécution (vous et votre femme avez un seul compte chèque).

Vous faites votre carte de débit en appelant le code comme ceci:

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

Votre femme fait son débit en même temps:

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

Qu'est-ce qui se passe si votre fil est interrompu par le fil de votre femme après que votre ancienne balance est imprimée à l'écran, mais avant que la nouvelle balance soit imprimée? Le thread de votre femme débite le compte et renvoie le contrôle à votre thread.Votre femme voit à l'écran:

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

Lorsque l'ordinateur imprime le nouvel équilibre sur votre écran, il sera faux, parce que le débit de votre femme aura été compté aussi. Vous verrez quelque chose comme ceci:

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

Pour résoudre ce problème, nous entourons notre code de méthode avec une instruction lock. L'instruction lock provoque l'attente de la fin de tous les autres threads. Le nouveau code ressemble à ceci:

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()); 
     } 
    } 
} 

le fil de votre femme va maintenant attendre votre code dans l'instruction de verrouillage pour terminer l'exécution, avant le code de votre femme commence à exécuter. Votre nouvelle balance sera maintenant correcte, car il n'y a plus la possibilité que le fil de votre épouse change la balance pendant que vous terminez votre transaction. Sur votre écran, vous verrez maintenant ceci:

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

Votre femme verra ceci:

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

Ceci est la synchronisation.

+0

Il y a aussi quelque chose appelé une variable conditionnelle. Voir cet article pour plus de détails: http://en.wikipedia.org/wiki/Monitor_%28synchronization%29 –

+0

L'épouse a une mauvaise sortie. 1900 - 50! = 1800 –

+0

@IgorGorjanc: Merci. –

2

Fondamentalement, il est un modèle de conception pour les fils qui ont besoin

a) synchroniser l'accès à une ressource

b) parfois attendre des autres threads jusqu'à ce qu'un certain conditions est remplie

Vous demandez cela dans un Contexte C#, .NET fournit un support pour cela avec Monitor.Wait et Monitor.Pulse (et avec des wrappers autour de divers objets Win32 comme WaitEventhandle).

Voici une belle queue example sur SO.

Les principaux détails techniques ressemblent:

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

Remarquez comment il y a une attente-en-verrouillé là-dedans. Cela ressemble à une impasse mais Wait relâchera le verrou pendant qu'il attend. Le code à l'intérieur du lock() { } a toujours un accès exclusif au tampon lorsqu'il s'exécute.

Et puis un autre thread doit signaler quand il met quelque chose dans la mémoire tampon:

Monitor.Pulse(buffer); 
1

Le code ci-dessus est presque correct, mais est réellement faux. En utilisant lock(this), vous ne verrouillerez que votre instance de la classe MyBanking, mais votre femme la verrouillera. Pour verrouiller l'accès à la variable partagée vous pouvez verrouiller le type (c.-à-lock(typeof(MyBanking))) ou vous pouvez introduire une nouvelle variable partagée et verrouiller que (vous ne pouvez pas verrouiller un int si généralement les gens créer un objet comme suit.

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

la synchronisation a été clairement expliqué déjà. Cependant, état synchronisation dicte spécifiquement qu'un processus/thread exécute uniquement après une condition est remplie. en règle générale, la condition sera qu'un autre processus/thread a déjà exécuté.

Dans l'exemple donné de débiter un compte et de visualiser le solde. Si l'affichage de votre solde était une méthode synchronisée distincte et que nous souhaitions afficher le solde uniquement après le débité de votre compte, cela impliquait une synchronisation des conditions.

La synchronisation des conditions est très bien décrite par le producer-consumer problem.