Programming/golang2026. 8. 25. 11:11

sync  패키지

[링크 : https://pkg.go.dev/sync]

 

Mutex.Lock() 은 Mutex.Unlock()으로 풀수 있다.

[링크 : https://pkg.go.dev/sync#Mutex.Lock]

[링크 : https://pkg.go.dev/sync#Mutex]

 

RWMutex.RLock() / RWMutex.Lock() - RWMutex.RUnlock() / RWMutex.Unlock()

abc 순으로 정렬되어있다보니 보기가 어렵네

아무튼 Lock - Unlock / RLock - RUnlock 으로 pair가 된다.

func (rw *RWMutex) Lock()
Lock locks rw for writing. If the lock is already locked for reading or writing, Lock blocks until the lock is available.


func (*RWMutex) Unlock ¶
func (rw *RWMutex) Unlock()
Unlock unlocks rw for writing. It is a run-time error if rw is not locked for writing on entry to Unlock.

As with Mutexes, a locked RWMutex is not associated with a particular goroutine. One goroutine may RWMutex.RLock (RWMutex.Lock) a RWMutex and then arrange for another goroutine to RWMutex.RUnlock (RWMutex.Unlock) it.


func (*RWMutex) RLock ¶
func (rw *RWMutex) RLock()
RLock locks rw for reading.

It should not be used for recursive read locking; a blocked Lock call excludes new readers from acquiring the lock. See the documentation on the RWMutex type.


func (*RWMutex) RUnlock ¶
func (rw *RWMutex) RUnlock()
RUnlock undoes a single RWMutex.RLock call; it does not affect other simultaneous readers. It is a run-time error if rw is not locked for reading on entry to RUnlock.

[링크 : https://pkg.go.dev/sync#RWMutex.Lock]

[링크 : https://pkg.go.dev/sync#RWMutex]

 

[링크 : https://www.jaenung.net/tree/28536]

[링크 : https://rainbow96bear.tistory.com/entry/Go-고루틴-이해하기-뮤텍스-데드락]

 

+

2026.08.26

Usage¶
To help diagnose such bugs, Go includes a built-in data race detector. To use it, add the -race flag to the go command:

$ go test -race mypkg    // to test the package
$ go run -race mysrc.go  // to run the source file
$ go build -race mycmd   // to build the command
$ go install -race mypkg // to install the package

[링크 : https://go.dev/doc/articles/race_detector]

'Programming > golang' 카테고리의 다른 글

golang channel..2 방향, select 등  (0) 2026.08.25
golang Init()  (0) 2026.08.20
golang git commit hash  (0) 2025.11.24
golang 정적웹 파일 포함하기  (0) 2025.11.24
go vet (golang 정적분석)  (0) 2025.10.02
Posted by 구차니
Programming/golang2026. 8. 25. 10:55

기본적으로 채널은 양방향이고, 생성시에 방향을 지정할수 있다

ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .

chan T          // can be used to send and receive values of type T
chan<- float64  // can only be used to send float64s
<-chan int      // can only be used to receive ints

[링크 : https://go.dev/ref/spec#Channel_types]

[링크 : https://mynewcodings.tistory.com/313]

[링크 : https://jh-labs.tistory.com/716]

 

채널 브릿징

[링크 : https://kr.linkedin.com/pulse/mastering-go-concurrency-comprehensive-guide-channel-sourav-choudhary-0nwbc?tl=ko]

 

 

+

2026.08.26

ch chan<- string 이라는 건 chan<- string 타입의 ch 변수로 해석을 하면 되는데

$ cat ch.go
package main

import "fmt"

// sendOnly: ch1에는 보내기만 가능
func sender(ch string chan<-) {
ch <- "안녕하세요!"
}

// recvOnly: ch1에서 받기만 가능
func receiver(ch <-chan string) {
msg := <-ch
fmt.Println(msg)
}

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

go sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨
receiver(ch)    // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨
}

 

ch string chan<- 을 허용하나 바꾸고 빌드해보는데 에러가 난다. 칫.

$ go build ch.go
# command-line-arguments
./ch.go:6:23: syntax error: unexpected keyword chan in parameter list; possibly missing comma or )

 

+

의도적으로 go를 붙이지 않아 고루틴으로 하지 않고 받는 걸 먼서 생성하고

블럭킹 되어있어서 보내는걸 실행하지 못하게 하면

$ cat ch.go 
package main

import "fmt"

// sendOnly: ch1에는 보내기만 가능
func sender(ch chan<- string) {
ch <- "안녕하세요!"
}

// recvOnly: ch1에서 받기만 가능
func receiver(ch <-chan string) {
msg := <-ch
fmt.Println(msg)
}

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

receiver(ch) // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨
sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨
// go sender(ch) // 혹은 이렇게
}

 

빌드 시에는 아무런 에러나 경고가 없지만

실행시에는 deadlock이라고 띄우준다. 오.. 좋은데?

$ ./ch
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.receiver(0x2a1f3ecc6738?)
/home/falinux/work/src/go/ch.go:12 +0x1e
main.main()
/home/falinux/work/src/go/ch.go:19 +0x26

 

둘다 go 붙여서 돌리면 받는 쪽이 느린건지 이상하게(?) 아무런 메시지도 나오지 않는다. 머지?

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

go receiver(ch) // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨
go sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨
}

 

그래서  sleep 추가해도 안되네?

claude 말로는 둘다 go 루틴 실행하고 main()의 끝에 도달해서 종료되는 바람에 그렇다고 한다.

$ cat ch.go 
package main

import (
"fmt"
"time"
)

// sendOnly: ch1에는 보내기만 가능
func sender(ch chan<- string) {
time.Sleep(100)
ch <- "안녕하세요!"
}

// recvOnly: ch1에서 받기만 가능
func receiver(ch <-chan string) {
msg := <-ch
fmt.Println(msg)
}

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

go receiver(ch) // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨
go sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨
}

 

그래서 아래와 같이 main 함수를 늦게 종료하면 정상적으로 잘 나온다.

많이는 하지 않았는데 놓치지 않는걸 보면 

받는 쪽에서는 블로킹 되어있고, 채널 자체는 큐에 차있다가 뺴갈수 있을때 전달이 되는 듯.

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

go receiver(ch) // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨
go sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨

time.Sleep(1000 * time.Millisecond)
}

 

 

+

양방향 전달은 의외로(?) 별거 없다.

그냥 chan<- <-chan 에서 <- 지우고 선언후, 당연하게(?) 보내고 받으면 된다.

$ cat ch.go 
package main

import (
"fmt"
"time"
)

// sendOnly: ch1에는 보내기만 가능
func sender(ch chan string) {
ch <- "안녕하세요!"

msg := <-ch
fmt.Println(msg)
}

// recvOnly: ch1에서 받기만 가능
func receiver(ch chan string) {
msg := <-ch
fmt.Println(msg)

ch <- "느그아부지 모하시노!"
}

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

go sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨
go receiver(ch) // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨

time.Sleep(1000 * time.Millisecond)
}

 

$ ./ch
안녕하세요!
느그아부지 모하시노!

 

+

len() 함수로 현재 채널 버퍼의 크기를 확인할 수 있고

cap() 함수로 채널 버퍼의 최대 크기를 확인할 수 있다

$ cat ch_cap.go 
package main

import "fmt"

func main() {
ch := make(chan int, 5) // 버퍼 크기 5인 채널 생성

ch <- 1
ch <- 2
ch <- 3

fmt.Println("현재 버퍼에 쌓인 개수:", len(ch)) // 3
fmt.Println("버퍼 전체 용량:", cap(ch))       // 5
}

$ go run ch_cap.go
현재 버퍼에 쌓인 개수: 3
버퍼 전체 용량: 5

[링크 : https://mynewcodings.tistory.com/313]

 

그런데 이상하게도 채널 크기를 지정하지 않으면 에러가 발생한다

$ cat ch_cap.go 
package main

import "fmt"

func main() {
ch := make(chan int) // 버퍼 크기 5인 채널 생성

ch <- 1
ch <- 2
ch <- 3

fmt.Println("현재 버퍼에 쌓인 개수:", len(ch)) // 3
fmt.Println("버퍼 전체 용량:", cap(ch))       // 5
}

$ go run ch_cap.go
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
/home/falinux/work/src/go/ch_cap.go:8 +0x36
exit status 2

 

claude 답변으로는 capacity를 지정하지 않으면 길이가 0이고, 보내는데 받는 쪽이 없어서 deadlock 발생한다고 판단한다고.

즉, 버퍼가 없지만 받아서 소비하지 않으면 계속 블러킹 되는건가?

The capacity, in number of elements, sets the size of the buffer in the channel. If the capacity is zero or absent, the channel is unbuffered and communication succeeds only when both a sender and receiver are ready. Otherwise, the channel is buffered and communication succeeds without blocking if the buffer is not full (sends) or not empty (receives). A nil channel is never ready for communication.

[링크 : https://go.dev/ref/spec#Channel_types]

 

그런데 그렇게 보기에는..

얘는 왜 컴파일도 문제 없고, 실행시에도 아무런 메시지 출력 안되고 (deadlock 안걸리고) 잘 종료되지?

claude 답변으로는 deadlock은 실제로는 쓰레드가 모두 잠들어서 깨지 못하는 상황을 탐지하는거라

main thread가 1초 뒤에 깰꺼고 "기브니 쪼꼬렛!"은 전송되지 못하고 기다리다 종료되는거라고

$ cat ch.go
package main

import (
"fmt"
"time"
)

// sendOnly: ch1에는 보내기만 가능
func sender(ch chan string) {
ch <- "안녕하세요!"
ch <- "기브미 쪼꼬렛!"

msg := <-ch
fmt.Println(msg)
}

// recvOnly: ch1에서 받기만 가능
func receiver(ch chan string) {
msg := <-ch
fmt.Println(msg)

ch <- "느그아부지 모하시노!"
}

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

go sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨
// go receiver(ch) // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨

time.Sleep(1000 * time.Millisecond)
}

 

실제로 단계별로 해보면 "안녕하세요!" 보내고 멈춰버렸다. 그렇군.

$ cat ch.go
package main

import (
"fmt"
"time"
)

// sendOnly: ch1에는 보내기만 가능
func sender(ch chan string) {
fmt.Println("run")
ch <- "안녕하세요!"
fmt.Println("wait")
ch <- "기브미 쪼꼬렛!"
fmt.Println("oops")

msg := <-ch
fmt.Println(msg)
}

// recvOnly: ch1에서 받기만 가능
func receiver(ch chan string) {
msg := <-ch
fmt.Println(msg)

ch <- "느그아부지 모하시노!"
}

func main() {
ch := make(chan string) // 생성할 때는 항상 양방향으로 만듦

go sender(ch)   // sender 함수 안에서는 송신만 가능하도록 타입이 제한됨
// go receiver(ch) // receiver 함수 안에서는 수신만 가능하도록 타입이 제한됨

time.Sleep(1000 * time.Millisecond)
}

 

$ go run ch.go
run

 

 

+

자꾸 헷갈리게 되는데

switch-case가 있고 select-case가 있다

select-case는 채널 전용 으로 생긴건 거의 유사한데

저렇게 값을 던지고 안보고 종료하는 용도로도 쓸 수 있나 보다.

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

[링크 : https://go.dev/tour/concurrency/5]

 

[링크 : https://go.dev/doc/effective_go#control-structures]

[링크 : https://go.dev/doc/effective_go#leaky_buffer]

 

claude 말로는 select에서 block 되어있어서

이를 이용해 타임아웃을 구현하는데 쓸 수 있다고 한다.

package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan string)

go func() {
time.Sleep(2 * time.Second)
ch <- "작업 완료"
}()

select {
case result := <-ch:
fmt.Println(result)
case <-time.After(1 * time.Second): // 1초 안에 ch가 준비 안 되면 여기 실행
fmt.Println("타임아웃!")
}
}

 

 

+

A channel may be closed with the built-in function close. The multi-valued assignment form of the receive operator reports whether a received value was sent before the channel was closed.

[링크 : https://go.dev/ref/spec#Channel_types]

 

A receive expression used in an assignment statement or initialization of the special form

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
var x, ok T = <-ch

[링크 : https://go.dev/ref/spec#Receive_operator]

'Programming > golang' 카테고리의 다른 글

golang mutex  (0) 2026.08.25
golang Init()  (0) 2026.08.20
golang git commit hash  (0) 2025.11.24
golang 정적웹 파일 포함하기  (0) 2025.11.24
go vet (golang 정적분석)  (0) 2025.10.02
Posted by 구차니
Programming/golang2026. 8. 20. 18:48

모듈에 init() 만들어 두면 일종의 constructor 처럼 자동으로 실행이 되는데

리턴도 없고 그래서 이래저래 제약이 있는 기능이라고 한다.

[링크 :  https://ray5273.tistory.com/entry/Golang-init-사용법-및-주의-사항]

 

func init() {
    if user == "" {
        log.Fatal("$USER not set")
    }
    if home == "" {
        home = "/home/" + user
    }
    if gopath == "" {
        gopath = home + "/go"
    }
    // gopath may be overridden by --gopath flag on command line.
    flag.StringVar(&gopath, "gopath", gopath, "override default GOPATH")
}

[링크 : https://go.dev/doc/effective_go#init]

'Programming > golang' 카테고리의 다른 글

golang mutex  (0) 2026.08.25
golang channel..2 방향, select 등  (0) 2026.08.25
golang git commit hash  (0) 2025.11.24
golang 정적웹 파일 포함하기  (0) 2025.11.24
go vet (golang 정적분석)  (0) 2025.10.02
Posted by 구차니
Programming/golang2025. 11. 24. 19:04

golang 에서 커밋 해시를 바이너리에 넣는 방법을 찾아보는 중

 

아래 방법은 링커에서 변수에 넣는것 같은데 이것도 쓸만해 보이긴 한데..

go build -ldflags "-X my/package/config.Version=1.0.0"

[링크 : https://www.reddit.com/r/golang/comments/rhpbvo/what_kind_of_things_have_you_ran_with_gogenerate/?tl=ko]

 

go version은 좀더 상세한 자료가 들어가는것 같은데 좀더 나은 접근 방법이 될 듯?

go version
The go command now embeds version control information in binaries. It includes the currently checked-out revision, commit time, and a flag indicating whether edited or untracked files are present. Version control information is embedded if the go command is invoked in a directory within a Git, Mercurial, Fossil, or Bazaar repository, and the main package and its containing main module are in the same repository. This information may be omitted using the flag -buildvcs=false.

Additionally, the go command embeds information about the build, including build and tool tags (set with -tags), compiler, assembler, and linker flags (like -gcflags), whether cgo was enabled, and if it was, the values of the cgo environment variables (like CGO_CFLAGS). Both VCS and build information may be read together with module information using go version -m file or runtime/debug.ReadBuildInfo (for the currently running binary) or the new debug/buildinfo package.

The underlying data format of the embedded build information can change with new go releases, so an older version of go may not handle the build information produced with a newer version of go. To read the version information from a binary built with go 1.18, use the go version command and the debug/buildinfo package from go 1.18+.

[링크 : https://tip.golang.org/doc/go1.18#go-command]

'Programming > golang' 카테고리의 다른 글

golang channel..2 방향, select 등  (0) 2026.08.25
golang Init()  (0) 2026.08.20
golang 정적웹 파일 포함하기  (0) 2025.11.24
go vet (golang 정적분석)  (0) 2025.10.02
golang 윈도우 서비스 프로그램 작성하기  (0) 2025.02.18
Posted by 구차니
Programming/golang2025. 11. 24. 18:59

내취향은 아니지만..

go generate 명령을 통해 코드를 생성하고 다시 빌드해서 넣는 듯

 

[링크 : https://go.dev/blog/generate]

[링크 : https://github.com/securego/gosec]

[링크 : https://ccambo.tistory.com/m/entry/Golang-의존성-없이-웹으로-서비스할-정적-파일들을-Golang-바이너리에-추가하기]

'Programming > golang' 카테고리의 다른 글

golang Init()  (0) 2026.08.20
golang git commit hash  (0) 2025.11.24
go vet (golang 정적분석)  (0) 2025.10.02
golang 윈도우 서비스 프로그램 작성하기  (0) 2025.02.18
golang tcp socket timeout 주기(listen, read)  (0) 2024.04.08
Posted by 구차니
Programming/golang2025. 10. 2. 10:54

'Programming > golang' 카테고리의 다른 글

golang git commit hash  (0) 2025.11.24
golang 정적웹 파일 포함하기  (0) 2025.11.24
golang 윈도우 서비스 프로그램 작성하기  (0) 2025.02.18
golang tcp socket timeout 주기(listen, read)  (0) 2024.04.08
golang reflect  (0) 2024.02.20
Posted by 구차니
Programming/golang2025. 2. 18. 14:27

리눅스에서 일반실행파일을 systemctl에 등록해서 실행하는것과 다르게

윈도우에서는 윈도우 서비스 api를 통해서 구동을 해야 정상적으로 구동된다.

 

일반적인 네트워크 echo 프로그램을 빌드해서 실행해보니

서비스 등록 문제 없음

서비스 실행 -> 실행중 -> 중지됨 으로 어느정도 시간이 지난후 멈춰버린다.

[링크 : https://pkg.go.dev/golang.org/x/sys/windows/svc]

 

[링크 : http://golang.site/go/article/116-윈도우즈-서비스-프로그램]

[링크 : http://www.toughman.pe.kr/2020/09/gogolang-언어로-윈도우즈-서비스-프로그램-만들기/]

'Programming > golang' 카테고리의 다른 글

golang 정적웹 파일 포함하기  (0) 2025.11.24
go vet (golang 정적분석)  (0) 2025.10.02
golang tcp socket timeout 주기(listen, read)  (0) 2024.04.08
golang reflect  (0) 2024.02.20
golang echo i18n  (0) 2024.02.19
Posted by 구차니
Programming/golang2024. 4. 8. 15:57

listen에서 accept 되면 write timeout은 조금 도외시 해도 되지 않을까 해서

read에만 timeout 하면 될 것 같아서 검색

 

 

conn.SetReadDeadline(time.Now().Add(timeoutDuration))

[링크 : https://gist.github.com/hongster/04660a20f2498fb7b680]

 

d := net.Dialer{Timeout: timeout}
conn, err := d.Dial("tcp", addr)
if err != nil {
   // handle error
}

[링크 : https://stackoverflow.com/questions/47117850/how-to-set-timeout-while-doing-a-net-dialtcp-in-golang]

'Programming > golang' 카테고리의 다른 글

go vet (golang 정적분석)  (0) 2025.10.02
golang 윈도우 서비스 프로그램 작성하기  (0) 2025.02.18
golang reflect  (0) 2024.02.20
golang echo i18n  (0) 2024.02.19
golang package  (0) 2024.02.19
Posted by 구차니
Programming/golang2024. 2. 20. 18:59

처음에는 이해를 못하고 넘겼는데, "런타임에 타입정보를 얻는" 이라고 하니 감이온다.

[링크 : http:// https://zetawiki.com/wiki/리플렉션,_리플렉티브_프로그래밍]

 

인터프리트 언어에서 성능 향상을 위해 런타임시 타입을 추적하는게 있었는데

그거 랑 유사하게 컴파일 언어지만 런타임 최적화를 위해서 추가된 기능이려나?

 

다만 리플렉트는 자바에서 온 듯

[링크 : https://a07274.tistory.com/m/53]

[링크 : https://pyrasis.com/book/GoForTheReallyImpatient/Uni6]

 

'Programming > golang' 카테고리의 다른 글

golang 윈도우 서비스 프로그램 작성하기  (0) 2025.02.18
golang tcp socket timeout 주기(listen, read)  (0) 2024.04.08
golang echo i18n  (0) 2024.02.19
golang package  (0) 2024.02.19
golang html/template ParseFiles()  (0) 2024.02.16
Posted by 구차니
Programming/golang2024. 2. 19. 15:22

echo 라이브러리에서도 i18n(다국어 지원)이 가능하단다.

근데 결국에는 이걸 쓰려면 템플릿을 이용해서 쇼를 해야하고,

템플릿은 서버 사이드에서 렌더링 해주는거라, 이래저래 매번 프로세싱을 해야 하는것도 부담이니

클라이언트 사이드에서 문자열 치환해서 넣는 방식으로 가야할 듯.

 

[링크 : https://phrase.com/blog/posts/internationalisation-in-go-with-go-i18n/]

[링크 : https://www.alexedwards.net/blog/i18n-managing-translations]

'Programming > golang' 카테고리의 다른 글

golang tcp socket timeout 주기(listen, read)  (0) 2024.04.08
golang reflect  (0) 2024.02.20
golang package  (0) 2024.02.19
golang html/template ParseFiles()  (0) 2024.02.16
golang runtime.GOMAXPROCS()  (0) 2024.02.15
Posted by 구차니