2016-09-30 80 views
4

因此,我将进一步使用golang并深入研究它提供的并发性。我决定尝试使用go例程来实现电话号码中字符串的排列。WaitGroup在之前的等待已返回之前被重用

我遇到了使用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*/ 
} 

排列/ perm.go

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

package intstack 

import "fmt" 

const (
    maxSize = 100 
) 

/*IntStack implimentaiton of a stack for integers*/ 
type IntStack struct { 
    valueList []int 
    maxSize int 
} 

/*New returns bew instace of IntStack*/ 
func New(nums []int) IntStack { 
    return IntStack{ 
     valueList: nums, 
     maxSize: maxSize, 
    } 
} 

/*Pop pops the top value off the stack*/ 
func (s *IntStack) Pop() int { 
    var val int 
    if !s.IsEmpty() { 
     val = s.valueList[0] 
     s.valueList = s.valueList[1:] 
    } else { 
     fmt.Println("stack is empty") 
    } 
    return val 
} 

/*Peek returns top value*/ 
func (s IntStack) Peek() int { 
    return s.valueList[0] 
} 

/*IsEmpty checks if the stack is empty*/ 
func (s IntStack) IsEmpty() bool { 
    if len(s.valueList) > 0 { 
     return false 
    } 
    return true 
} 

/*Print prints out the contents of the stack*/ 
func (s IntStack) Print() { 
    for _, element := range s.valueList { 
     fmt.Print(element) 
    } 
    fmt.Print("\n") 
} 

因此经过研究,在wg.Wait()或rathe等待组等待函数期间调用该行。我试图复制一个较小的程序,但不能。我的假设是一旦它在调用go例程之后到达Wait(),我们就不能再编辑等待组了,但这听起来不对。任何洞察为什么会发生的事情将是有益的

回购做参考,可以发现:https://github.com/sbiscigl/phonenumberperm

回答

6

在你的递归情况下ThreadSafeCalcWords,调用wg.Add之前你打电话wg.Done。这意味着在你完成所有工作之前,wg可以下降到0(这将触发Wait完成)。再次调用Add,而Wait仍处于解析过程中会触发错误,但更重要的是,它可能只是简单的不是你想要的。

更改操作顺序,使您始终在做Done之前的任何新工作,并且Wait不会过早触发。完成此操作的最简单方法可能是在函数底部调用wg.Done(),或顶部调用一个defer,然后删除所有其他调用。

相关问题