2011-11-25 1 views
-2

Je veux écrire trois routines go simultanées qui envoient des entiers les uns aux autres. Maintenant, mon code est compilé correctement, mais après la première exécution il donne l'erreur "throw: tous les goroutines sont endormis - deadlock!". J'ai essayé de trouver l'erreur mais je ne pourrais pas trouver n'importe quelle erreur dans la logique de code. Peut-on m'aider à trouver l'erreur avec mon code. Mon code est donné ci-dessous.jeter tous les goroutines sont endormis - impasse! ------- Erreur dans Google GO

package main 

import "rand" 

func Routine1(command12 chan int, response12 chan int, command13 chan int, response13 chan int) { 

    // z12 is a variable which stores the value comming from channel 2 and z13 is a variable which stores the value comming from channel 3. 

    z12 := 200 
    z13 := 200 
    m12 := false 
    m13 := false 
    y := 0 

    for i := 0; i < 20; i++ { 
     y = rand.Intn(100) 

     // If y's value is not 0 then the value will be sent to routine 2 or 3 according to prime or not. 
     // If y's value is 0 then process state (the varibles used by it means z12, z13) and channel state will be saved.[routine 1 is initiator] 

     if y == 0 { 
      print(z12, " z12 STATE SAVED\n") 
      print(z13, " z13 STATE SAVED\n") 

      // Routine 1 is initiator, it sends 0 to make other process to save the state. 

      y = 0 
      command12 <- y 
      command13 <- y 

      // Untill routine 2 and 3 does not send 0, process 1 is on channel saving state (it's process state is already saved). 
      // When routine 1 recives 0 from both other processes, channel is saved and routine 1 retuns to it's common routine procedure. 
      // When routine 1 recives 0 from any other processes, saving channel bettwen them is stopped. 
      // m12, m13 is used to mark whether 0 recived or not. 

      for m12 != true || m13 != true { 
       select { 
       case cmd1 := <-response12: 
        { 
         z12 = cmd1 
         if z12 != 0 { 
          print(z12, " z12 Channel Saving.... \n") 
          y = rand.Intn(100) 
          command12 <- y 
         } 
         if z12 == 0 { 
          m12 = true 
          print(" z12 Channel Saving Stopped \n") 
         } 
        } 

       case cmd2 := <-response13: 
        { 
         z13 = cmd2 
         if z13 != 0 { 
          print(z13, " z13 Channel Saving.... \n") 
          y = rand.Intn(100) 
          command13 <- y 
         } 
         if z13 == 0 { 
          m13 = true 
          print(" z13 Channel Saving Stopped \n") 
         } 
        } 
       } 

      } 

      // After saving process state it retuns to it's normal behaviour. 

      m12 = false 
      m13 = false 
     } 

     if y != 0 { 

      // If y value is not 0, routine 1 just sends int to other process according to prime or not and recives int accordingly. 

      if y%2 == 0 { 
       command12 <- y 
      } 

      if y%2 != 0 { 
       command13 <- y 
      } 
      select { 
      case cmd1 := <-response12: 
       { 
        z12 = cmd1 
        print(z12, " z12\n") 
       } 
      case cmd2 := <-response13: 
       { 
        z13 = cmd2 
        print(z13, " z13\n") 
       } 
      } 
     } 
    } 
    close(command12) 
    close(command13) 
} 


//Routine 2 (or 3) is not an initiator (means it can't send 0). When it recives 0 (from routine 1 or 3) it save the state of process and the state of the channel from which it recived). 
// When it recives 0 from both other two routine, it saves all channel state and returns to it's common behaviour. [same in routine 3] 

func Routine2(command12 chan int, response12 chan int, command23 chan int, response23 chan int) { 
    z21 := 200 
    z23 := 200 
    m21 := false 
    m23 := false 

    for i := 0; i < 20; i++ { 
     select { 
     case x, open := <-command12: 
      { 
       if !open { 
        return 
       } 
       if x != 0 && m23 != true { 
        z21 = x 
        print(z21, " z21\n") 
       } 
       if x != 0 && m23 == true { 
        z21 = x 
        print(z21, " z21 Channel Saving \n") 
       } 
       if x == 0 { 
        m21 = true 
        if m21 == true && m23 == true { 
         print(" z21 and z23 Channel Saving Stopped \n") 
         m23 = false 
         m21 = false 
        } 
        if m21 == true && m23 != true { 
         z21 = x 
         print(z21, " z21 Channel Saved \n") 

        } 

       } 
      } 

     case x, open := <-response23: 
      { 
       if !open { 
        return 
       } 
       if x != 0 && m21 != true { 
        z23 = x 
        print(z23, " z21\n") 
       } 
       if x != 0 && m21 == true { 
        z23 = x 
        print(z23, " z23 Channel Saving \n") 
       } 
       if x == 0 { 
        m23 = true 
        if m21 == true && m23 == true { 
         print(" z23 Channel Saving Stopped \n") 
         m23 = false 
         m21 = false 
        } 
        if m23 == true && m21 != true { 
         z23 = x 
         print(z23, " z23 Channel Saved \n") 
        } 

       } 
      } 
     } 

     if m23 == false && m21 == false { 
      y := rand.Intn(100) 
      if y%2 == 0 { 
       if y == 0 { 
        y = 10 
        response12 <- y 
       } 
      } 

      if y%2 != 0 { 
       if y == 0 { 
        y = 10 
        response23 <- y 
       } 
      } 
     } 

     if m23 == true && m21 != true { 
      y := rand.Intn(100) 
      response12 <- y 
     } 

     if m23 != true && m21 == true { 
      y := rand.Intn(100) 
      command23 <- y 
     } 

    } 
    close(response12) 
    close(command23) 
} 

func Routine3(command13 chan int, response13 chan int, command23 chan int, response23 chan int) { 
    z31 := 200 
    z32 := 200 
    m31 := false 
    m32 := false 

    for i := 0; i < 20; i++ { 
     select { 
     case x, open := <-command13: 
      { 
       if !open { 
        return 
       } 
       if x != 0 && m32 != true { 
        z31 = x 
        print(z31, " z21\n") 
       } 
       if x != 0 && m32 == true { 
        z31 = x 
        print(z31, " z31 Channel Saving \n") 
       } 
       if x == 0 { 
        m31 = true 
        if m31 == true && m32 == true { 
         print(" z21 Channel Saving Stopped \n") 
         m31 = false 
         m32 = false 
        } 
        if m31 == true && m32 != true { 
         z31 = x 
         print(z31, " z31 Channel Saved \n") 

        } 

       } 
      } 

     case x, open := <-command23: 
      { 
       if !open { 
        return 
       } 
       if x != 0 && m31 != true { 
        z32 = x 
        print(z32, " z32\n") 
       } 
       if x != 0 && m31 == true { 
        z32 = x 
        print(z32, " z32 Channel Saving \n") 
       } 
       if x == 0 { 
        m32 = true 
        if m31 == true && m32 == true { 
         print(" z32 Channel Saving Stopped \n") 
         m31 = false 
         m32 = false 
        } 
        if m32 == true && m31 != true { 
         z32 = x 
         print(z32, " z32 Channel Saved \n") 

        } 

       } 
      } 
     } 
     if m31 == false && m32 == false { 
      y := rand.Intn(100) 
      if y%2 == 0 { 
       response13 <- y 
      } 

      if y%2 != 0 { 
       response23 <- y 
      } 
     } 

     if m31 == true && m32 != true { 
      y := rand.Intn(100) 
      response13 <- y 
     } 

     if m31 != true && m32 == true { 
      y := rand.Intn(100) 
      response23 <- y 
     } 

    } 
    close(response13) 
    close(response23) 
} 


func main() { 

    // Three concurrent channels are created to pass integers to each other. 
    // command 12 used to send int and response12 is used to receive int from routine 1 to routine 2. 
    // response 12 used to send int and command 12 is used to receive int from routine 2 to routine 1. {so as for others} 

    command12 := make(chan int) 
    response12 := make(chan int) 
    command13 := make(chan int) 
    response13 := make(chan int) 
    command23 := make(chan int) 
    response23 := make(chan int) 

    go Routine1(command12, response12, command13, response13) 
    go Routine2(command12, response12, command23, response23) 
    Routine3(command13, response13, command23, response23) 
} 
+1

Vous devriez probablement supprimer tout ce qui ne fait pas partie de votre problème. Si vous avez toujours votre problème, publiez ce code, de préférence bien formaté. – Dustin

+0

Je n'ai pas supprimé tous ces commentaires parce que selon mon point de vue, cela rendra mon intention claire. Nd sur le format, veuillez préciser comment je devrais le faire mieux. Merci. – Arpssss

+3

Je suis sûr que Dustin ne parle pas de commentaires. Essayez de reproduire le problème avec moins de code. De meilleurs noms pour vos variables et fonctions seraient également utiles. –

Répondre

3

Comme d'autres ont dit - votre code est trop complexe pour moi de trouver rapidement sa logique destinée. Quoi qu'il en soit, une approche "d'analyse technique" a apporté quelques petits détails. Lors de l'ajout de Gosched en tant que cas par défaut aux instructions de sélection et rendant les canaux mis en mémoire tampon - alors le code ne bloque plus les blocages. Bien que je n'ai aucune idée de ce qu'il fait et s'il fait ce que vous voulez qu'il fasse.

Il me semble, en regardant le code, que le comportement est non déterministe (?). En tout cas, je pense que le code original est probablement cassé par la conception (par exemple, certaines boucles semblent être occupées, même si elles exécutent un N en dur, sic!), Désolé de le dire.

Le « travail » (== qui sait ce qu'il fait) Code: http://play.golang.org/p/dcUpeJ9EUa

PS: La taille du tampon const @ ligne 325 ne peut pas laisser tomber ci-dessous 4 (par essai fonctionne avec toutes les semaines) et semble fournir une autre façon de changer le comportement du code.

+0

Merci beaucoup jnml. – Arpssss

1

Je ne connais pas la réponse à votre problème, mais la déclaration switch dans Routine3 regarde poussette car il contient deux déclarations identiques case (ce qui me fait me demande pourquoi 6g ne se plaint pas de ce code).

Quelques suggestions pour rendre votre code plus lisible:

  • Comme Evan a déjà souligné, essayez de trouver des noms plus descriptifs pour vos variables. Code qui lit if someConditionIsMet est plus facile à comprendre que if m23 == false.
  • Sécher votre code en factorisant des parties communes dans des fonctions.
  • Supprimez le code mort, par exemple en définissant une valeur booléenne sur true, puis en vérifiant si elle est vraie ou en vérifiant si un nombre impair est égal à zéro.
  • Pensez à utiliser else au lieu de if <condition> {...}; if <negated condition> {...}

Je recommande d'essayer de trouver des tests unitaires qui décrivent de manière exhaustive le comportement attendu de vos fonctions. Cela vous aidera non seulement à trouver le bug, mais aussi à améliorer vos compétences de codage. D'après mon expérience, le code écrit avec des tests à l'esprit est souvent plus facile à comprendre, maintenir et évoluer que le code non testé.

Happy Hacking :)

Questions connexes