2017-09-15 12 views
-2
package main 

var fooRunning = false 
var barRunning = false 

func foo() { 
    fooRunning = true 
    defer func() { fooRunning = false }() 
    if barRunning { 
     // wait for bar() to finish 
    } 
    ... 
} 

func bar() { 
    barRunning = true 
    defer func() { barRunning = false }() 
    if fooRunning { 
     // wait for foo() to finish 
    } 
    ... 
} 

go foo()을 실행하면 bar()이 끝날 때까지 기다려야하며, 그 반대의 경우도 마찬가지입니다. 가장 좋은 방법은 무엇입니까? 그것들은 또한 독립적으로 실행될 수 있습니다.하나 이상의 goroutine이 끝날 때까지 기다리는 방법은 무엇입니까?

+1

관련/가능한 [이 골란 코드에 문제가 있습니까?] (https://stackoverflow.com/questions/28958192/whats-wrong-with-this-golang-code?noredirect=1&lq=1) – icza

+2

요구 사항이 제대로 처리되어야하는 엄청난 수의 경쟁 조건을 야기합니다 (다른 루틴이 사후 점검 직후에 끝나면 어떻게됩니까? 네거티브 체크 후에 다른 루틴을 시작하면 어떻게됩니까?) 누군가가 foo의 2 루틴을 실행하면()) 나는 당신이 서로 독립적 인 달리기 상태에 상호 의존적 인 2 개의 goroutine을 가지지 않는 더 나은 디자인을 만들 것을 강력하게 촉구한다. – nos

+1

질문에있는 코드는 @nos로 표시된 교착 상태가 있습니다. 주어진 시나리오에서 작동 할 솔루션이 없습니다. – Adrian

답변

-1

채널을 사용할 수 있습니다! 난 내 녹슨 이동에서 기억으로,이 줄 것이다 :

func foo() { 
    c := make(chan int) 
    go bar(c) 
    <-c 
} 

과 당신의 요구 사항이 어떤 구체적인 설계에 의해 안전하게 만족할 수없는 바

func bar(c chan int) { 
    // do stuff here 
    c <- 0 
} 
+0

bar()가 실행되지 않으면 어떻게됩니까? 채널이 추가 실행을 차단합니다. 맞습니까? –

+0

예, 다른 goroutine이 채널의 정수를 푸시하지 않으면, 더 많은 정수가 주어질 때까지'<-c'가 차단됩니다. 'bar'에서 채널에 정수를 보내는 것을 잊어 버리면 프로그램은 교착 상태가됩니다. –

+1

이것은 단방향 블록킹만을 제공합니다. 그것은 문제의 설계된 교착 상태를 해결하지 못한다. 그것은 불필요하게 채널을 사용합니다. ['sync.WaitGroup'] (https://golang.org/pkg/sync/#WaitGroup)은이 사용 사례를 위해 제작되었지만 교착 상태가 제거 될 때까지 솔루션을 제안 할 수 없습니다. – Adrian

0

에 있습니다. 처방대로, foobar이 동시 goroutines에서 실행되며, 둘 중 하나 또는 둘 다 시작된 경우 다른 하나는 완료 될 때까지 기다려야한다고 말합니다. 그것은 처방전이 너무 약합니다. foo이 시작된 후 끝나지 만 bar이 아직 실행되지 않으면 어떻게됩니까? bar 전혀 실행되지 않으면 어떻게됩니까? 또는 bar이 실행되면 foo이 실행되지 않으면 어떻게됩니까?

foobar 모두 프로그램을 올바르게 시작하기 위해 시작해야하며 완료해야합니까? 그렇다면 당신이 처방하려는 내용을 짐작할 수 있습니다 : 진행하기 전에 모두 완료되기를 기다리는 barrier을 원합니다.

package main 

import (
    "fmt" 
    "sync" 
    "time" 
) 

func foo() { 
    fmt.Println("foo") 
} 

func bar() { 
    fmt.Println("bar") 
} 

func within(wg sync.WaitGroup, f func()) { 
    wg.Add(1) 
    go func() { 
     defer wg.Done() 
     f() 
    }() 
} 

func main() { 
    var wg sync.WaitGroup 
    within(wg, foo) 
    within(wg, bar) 
    wg.Wait() 
    fmt.Println("Both foo and bar completed.") 
} 

(That same example in the Playground) 여기, foobar도 상호 인식

참고; 두 사람의 전화를 조화시키기 위해 전화 한 사람 만 있습니다. foobar 각각 종료하기 전에 adding itself to the groupwaiting on it 먼저 각 기능, 매개 변수 sync.WaitGroup로여 닫거나 동의를 만드는 길을 당신을 이끌 수

원래 시도. 그 방법은 광기를 속인다.

만약 foo가 시작되고 barWaitGroup에 자신을 추가 할 수있는 기회를하기 전에, foo 당신이 그들이 동시에 실행했다 주장, 또는 foo가 활성을 등록 할 수 있습니다 전에 bar 실행과 대화 할 수있다하더라도, bar 전에 종료됩니다 완료 상태. 다시 말하지만, 이것은 프로그램의 잘못 지정된 부분이기 때문에,이 두 함수의 상호 의존성이 아니라 상위 레벨의 장벽에 집중하는 것이 좋습니다.