채널은 데이터를 주고 받을 수 있는 통로임.
이 포스팅에서는 버퍼 없는 채널의 작동 방시에 대해 작성함.
버퍼 없는 채널의 경우 데이터 주는 것과 데이터를 받는 것이 정확히 같은 시간에 이루어져야 함.
이 특성으로 쌍방향 무한 대기(blocking) 상태가 나타남.
고루틴 없이 메인 함수 안에서 채널로 데이터를 주고 받으면 데드락 발생함.
package main
import "fmt"
func main() {
ch := make(chan int) // 버퍼 없는 채널 생성
ch <- 1 // [1] 데이터를 보냄 (여기서 멈춤!)
result := <-ch // [2] 데이터를 받음
fmt.Println(result)
}
[1]에서 무한 대기가 발생하고 영원히 아래 라인으로 넘어갈 수 없음. 혼자서 데이터를 주지도 받지도 못하고 영원히 멈춰있는 데드락 상태에 빠짐.
위의 데드락을 해결하기 위해서 데이터는 동시에 주고 받아야 함.
package main
import "fmt"
func main() {
ch := make(chan int)
// 새로운 심부름꾼(고루틴) 생성
go func() {
ch <- 1 // 고루틴이 데이터를 보내고 대기함
}()
result := <-ch // 메인 함수는 여기서 대기하다가, 고루틴이 1을 주면 받음
fmt.Println(result)
}
고루틴을 사용하면 데이터를 동시에 주고 받을 수 있으므로 데드락 없이 다음 작업이 진행됨.
채널의 블로킹 성질을 활용하여 백그라운드 서버를 만들 때 프로그램 강제 종료를 막을 수 있음.
func main() {
// 1. 메시지를 처리하는 백그라운드 고루틴들을 실행
go catalogManager.MenuHandler()
go catalogManager.SubMessage(ch)
fmt.Println("Catalog Manager가 실행 중입니다...")
// 2. 종료 방지용 'forever' 채널 생성
forever := make(chan bool)
// 3. 아무도 값을 넣어주지 않는 채널을 대기함
<-forever
}
채널에 아무도 데이터를 주지 않기 때문에 영원기 대기하게 되어 main 함수가 종료되지 않고 백그라운드의 고루틴들이 종료되지 않고 계속 돌아가게 됨.
이때 백그라운드에서 다른 고루틴이 실행되고 있기 때문에 데드락이 발생하지 않음.