2016-09-30 4 views
4

これで、golangを使用して、それが提供する並行性をより詳しく調べていきます。私はgoルーチンを使用して電話番号の文字列の順列を実装しようと決めました。WaitGroupは以前のWaitが返される前に再利用されます

私は、使用しているgoルーチンを調整するためにsync.WaitGroupを使用している問題に遭遇しています。特定のエラービーイング:

WaitGroup is reused before previous Wait has returned

コードビーイング:

main.go

package main 

import (
    "fmt" 
    "sync" 

    "github.com/sbiscigl/phonenumberperm/intstack" 
    "github.com/sbiscigl/phonenumberperm/permutations" 
) 

var wg sync.WaitGroup 

func main() { 
    num := []int{2, 7, 1, 4, 5, 5, 2}  
    stack := intstack.New(num) 
    permutationChannel := make(chan string) 
    wg.Add(1) 
    go permutations.ThreadSafeCalcWords(stack, "", permutationChannel, &wg) 
    wg.Wait() 
    /*Then consume, but not implimented*/ 
} 

順列/

package permutations 

import (
    "fmt" 
    "sync" 

    "github.com/sbiscigl/phonenumberperm/intstack" 
) 

var letterMap = map[int][]string{ 
    2: []string{"a", "b", "c"}, 
    3: []string{"d", "e", "f"}, 
    4: []string{"g", "h", "i"}, 
    5: []string{"j", "k", "l"}, 
    6: []string{"m", "n", "o"}, 
    7: []string{"p", "q", "r", "s"}, 
    8: []string{"t", "u", "v"}, 
    9: []string{"w", "x", "y", "z"}, 
} 

func ThreadSafeCalcWords(s intstack.IntStack, word string, ch chan<- string, 
    wg *sync.WaitGroup) { 
    if s.IsEmpty() { 
     ch <- fmt.Sprint(word) 
     wg.Done() 
    } else { 
     /*Check to see if the values are 1 or zero as they*/ 
     /*have no letters associated with them*/ 
     if s.Peek() == 1 || s.Peek() == 0 { 
      wg.Done() 
      s.Pop() 
      wg.Add(1) 
      go ThreadSafeCalcWords(s, word, ch, wg) 
     } else { 
      wg.Done() 
      for _, letter := range letterMap[s.Pop()] { 
       wg.Add(1) 
       go ThreadSafeCalcWords(s, word+letter, ch, wg) 
      } 
     } 
    } 
} 

intstack/intstack.go

perm.go

したがって、調査の後、その行がwg.Wait()またはwaitheの待機中に呼び出されます。私は小さなプログラムで再現しようとしましたが、できませんでした。私の仮説は、goルーチンを呼び出した後にWait()に達すると、もはや待機グループを編集できなくなるが、それは間違っているということです。これが起こってしまう理由に任意の洞察力がrefrenceため

レポはで見つけることができ、参考になる:ThreadSafeCalcWordsであなたの再帰的な例ではhttps://github.com/sbiscigl/phonenumberperm

答えて

6

、あなたはwg.Addを呼び出す前wg.Doneを呼んでいます。つまり、実際にすべての作業を完了する前に、wgを0にして(Waitを起動させる)ことができます。 Waitが依然として解決の過程にある間にAddを再度呼び出すと、エラーがトリガーされますが、もっと重要なことは、おそらく単純なことはあなたが望むものではないということです。

変更操作の順序は、必ず既存の作業にDoneを行う前に、新しい仕事をAdd、そしてWaitが早まってトリガされませんように。これを実現する最も簡単な方法は、関数の末尾にあるwg.Done()への1回の呼び出しか、最上部にあるdeferの1回の呼び出しであり、他のすべてを取り除くことです。

関連する問題