본문 바로가기
golang

golang signal과 context 기초

by PudgeKim 2021. 4. 6.

golang에서는 signal과 context를 이용하여 여러가지 제어를 할 수 있습니다.

 

먼저 signal 제어 방법을 알아볼건데 syscall.SIGINT 와 syscall.SIGTERM 을 알아보겠습니다.

syscall.SIGINT는 ctrl+c 에 대한 시그널이고 syscall.SIGTERM은 종료에 대한 시그널입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
 
import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)
 
func main() {
    cancelChan := make(chan os.Signal)
    signal.Notify(cancelChan, syscall.SIGINT, syscall.SIGTERM)
    
    go func() {
        fmt.Println("goroutine works!")
        cancelChan <- syscall.SIGTERM
    }()
 
    sig := <-cancelChan
    fmt.Println("main end", sig)
}
cs

위 코드는 SIGTERM을 받은 예제입니다.

main function은 cancelChan으로부터 시그널이 올 때 까지 기다립니다. (즉, 시그널이 올 때 까지 fmt.Println이 실행되지 않습니다.)

go function이 "goroutine works! terminated"를 출력 후에 cancelChan으로 종료 시그널을 보내면 main function이 시그널을 받고 "main end"가 출력되고 프로그램이 종료됩니다. sig는 출력해보면 terminated라고 나옵니다. 종료 시그널을 의미합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
 
import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)
 
func main() {
    cancelChan := make(chan os.Signal)
    signal.Notify(cancelChan, syscall.SIGINT, syscall.SIGTERM)
 
    fmt.Println("waiting...")
 
    sig := <-cancelChan
    fmt.Println("main end", sig)
}
cs

위 코드는 syscall.SIGINT에 대한 예제입니다. 코드를 실행하면 "waiting..."이 출력되고 더 이상 프로그램이 진행되지 않습니다.

sig := <-cancelChan 이 부분에서 멈춰있기 때문입니다. ctrl+c로 시그널을 주면 sig가 채널로부터 시그널을 받고 "main end interrupt"가 출력되고 종료 됩니다. interrupt는 syscall.SIGINT를 의미합니다.

 

이제 context와 타임아웃에 대해 알아보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main
 
import (
    "context"
    "fmt"
    "time"
)
 
 
 
func Ping(sigChan chan struct{}){
    fmt.Println("ping departed")
    time.Sleep(5*time.Second)
    sigChan <- struct{}{}
    fmt.Println("ping arrived")
}
 
 
func main() {
    rootCtx := context.Background()
    ctx, cancel := context.WithTimeout(rootCtx, 3*time.Second)
    defer cancel()
 
    ch := make(chan struct{})
    go Ping(ch)
 
 
    select {
        case <- ctx.Done():
            fmt.Println("terminated by timeout")
 
        case <- ch:
            fmt.Println("terminated by ping")
 
    }
 
}
cs

Ping함수는 보다시피 "ping departed"를 출력 후에 5초를 기다린 후 채널에 empty struct를 보내고 도착을 했다고 알립니다.

main함수를 보면 context.WithTimeout함수를 통해 3초 후에 알림이 오게 설정해놓았습니다.

그 후 go Ping(ch)을 통해 Ping함수는 고루틴으로 비동기 처리가 됩니다.

그리고 select문을 통해 context로 부터 알림을 받거나 Ping이 도착했을 때(채널에 struct{}{}를 보내므로) 알림을 받을 수 있습니다.

그런데 예제에서 Ping함수는 채널에 struct{}{}를 보낼 때까지 5초가 걸리고 timeout은 3초이므로 ctx.Done()함수에 의해 3초 후에 타임아웃 알림을 받고 "terminated by timeout"이 출력되고 프로그램은 종료됩니다.

'golang' 카테고리의 다른 글

Golang network#2 tcp buffer  (0) 2021.04.12
golang cancel과 waitGroup 기초  (0) 2021.04.11
Golang network TCP hello world 예제  (0) 2021.04.05
golang에서 heap 사용하기  (0) 2021.04.03
golang 인터페이스 활용  (0) 2021.03.25