2016-08-16 3 views
1

채널에 쓰는 함수 (클로저가 아님)가 있습니다. 내가goroutine을 사용하여 채널을 통해 동시 함수를 읽는 중 오류가 발생하는 클로저

var wg sync.WaitGroup 
wg.Add(1) 
go DoStuff(somechan, &wg) 

내부 DoStuff로 goroutine에서 해당 함수를 호출하고, 나는

for ; ; { 

    if err == io.EOF { 
     fmt.Println(err) 
     close(somechan) 
     fmt.Println("Closed channel") 
     break 
    } else if err != nil { 
     panic(err) 
    } 
    somechan <- Somefunc() 
} 

같은 일이 지금은 다른 goroutine을 사용하여 해당 채널에서 읽을 노력하고 있습니다. 실행 그러나

wgread.Add(1) 
go func() { 
    for ; ; { 
     select { 
     case chanoutput, ok := <-somechan: 
      if ok == true { 
       fmt.Println(string(*chanoutput)) 
      } else { 
       fmt.Println("DONE") 
       fmt.Println(ok) 
       wgread.Done() 
       break 
      } 
     } 

    } 
}() 
wgread.Wait() 

, 나는

DONE 
false 
DONE 
false 

내가주는 경우에 wgread.Add (2)는 위 DONE과 거짓 3 인쇄 할 인쇄 후

panic: sync: negative WaitGroup counter 

무엇입니까 타임스.

대기 그룹 델타를 1 씩 증가 시켰지만 음의 대기 그룹 카운터 오류가 발생하는 이유는 무엇입니까? 다른 동시 함수 또는 클로저를 사용하여 goroutine에서 읽는 가장 좋은 방법은 무엇입니까?

+0

wgread.Wait()-wgread.Add(1)의 코드를 교체 문제를 말할 여기에 코드의 충분하지 않습니다. –

답변

3

break 문은 for 또는 switch 문 내부 가장 큰 경우에서 나옵니다. somechan에서 수신하는 함수는 채널이 닫힐 때 대기 그룹을 감소시키는 루프에서 회전합니다. 다음과 같은 코드를 작성하십시오 :

wgread.Add(1) 
go func() { 
    defer wgread.Done() 
    for chanoutput := range somechan { 
     fmt.Println(string(*chanoutput)) 
    } 
    fmt.Println("DONE") 
}() 
wgread.Wait() 

수신 코드가 질문에 쓰여 있으면 수신 goroutine을 제거 할 수 있습니다.

for chanoutput := range somechan { 
    fmt.Println(string(*chanoutput)) 
} 
3

break은 바깥 쪽 루프를 깨지 않습니다. for 는이 같은 라벨을 사용하여, 외부 루프를 참조하려면 :

Loop: 
    for { 
     select { 
      case ...: 
       break Loop 
     } 
    } 

또한 당신이 당신의 코드를 포맷 gofmt를 사용하여 연습해야 코딩 스타일에 도움이. 예를 들어 for ; ; { ... }을 청소기 for { ... }으로 바꿉니다.

+0

감사합니다 @Baloo,하지만 Break Loop를 사용하면 주 스레드가 대기 중입니다. – scott