[Go] data race์™€ mutex, atomic

Go๋Š” ๊ณ ๋ฃจํ‹ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ฑ๋Šฅ์ ์œผ๋กœ ๋นผ์–ด๋‚œ ๋น„๋™๊ธฐ ์‹œ์Šคํ…œ์„ ์ œ๊ณตํ•˜๊ธฐ๋Š” ํ•˜์ง€๋งŒ, ๋™๊ธฐํ™”์— ๋Œ€ํ•œ ์•ˆ์ „์„ฑ์— ์—„๊ฒฉํ•˜์ง€๋Š” ์•Š๋‹ค. Rust์ฒ˜๋Ÿผ ๋นก์„ธ๊ฒŒ ๋™์‹œ์„ฑ์„ ๊ฒ€์‚ฌํ•˜์ง€๋Š” ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„ ์ƒ๊ฐ์—†์ด ์งœ๋‹ค๊ฐ€๋Š” ๋™์‹œ์„ฑ ๋ฒ„๊ทธ๊ฐ€ ๋‚˜๊ธฐ ์‰ฝ๋‹ค.

์ด๋Ÿฐ ๊ฒƒ์— ๋Œ€ํ•œ ๋Œ€ํ‘œ์ ์ธ ์‚ฌ๋ก€ ์ค‘ ํ•˜๋‚˜๊ฐ€ data race์ผ๊ฒƒ ๊ฐ™๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋Š” data race๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋‹ค.
๊ณ ๋ฃจํ‹ด 10๊ฐœ๋ฅผ ๋Œ๋ ค์„œ ๋‹จ์ผ ๊ณต์œ ๋ณ€์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋‹จ์ˆœํ•œ ๋กœ์ง์„ ๊ฐ–๊ณ  ์žˆ๋‹ค.

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	var shared = 0

	// ๊ณ ๋ฃจํ‹ด 10๊ฐœ ๋„์šฐ๊ธฐ
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			// ๊ฐ ๊ณ ๋ฃจํ‹ด์€ ๊ณต์œ ๋ณ€์ˆ˜๋ฅผ 10000๋ฒˆ์”ฉ ์ฆ๊ฐ€์‹œํ‚ด
			for j := 0; j < 10000; j++ {
				shared++
			}
		}()
	}

	wg.Wait()
	fmt.Println(shared) // 10 * 10000 = 100000๊ฐ€ ๋‚˜์™€์•ผ ํ•˜๋Š”๋ฐ...?
}

์šฐ๋ฆฌ์˜ ๊ธฐ๋Œ€๋Œ€๋กœ๋ผ๋ฉด ๋‹น์—ฐํžˆ 10๋งŒ์ด ์ฐํ˜€์•ผ ํ•˜๊ฑด๋งŒ

10๋งŒ์ด ๋‚˜์˜ค์ง€๋„ ์•Š๊ณ , ์ผ์ •ํ•œ ๊ฐ’์ด ๋‚˜์˜ค์ง€๋„ ์•Š๋Š”๋‹ค.
์ด๊ฑธ ๋ฐ์ดํ„ฐ ๋ ˆ์ด์Šค๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๋ฐ, ์—ฌ๋Ÿฌ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ํ•˜๋‚˜์˜ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๋‹ˆ๊นŒ, ๊ฐ์ž์˜ ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ๊ฐ€ ์„œ๋กœ ์ถฉ๋Œํ•˜๋ฉด์„œ ์„œ๋กœ์„œ๋กœ ๋ฎ์–ด์”Œ์›Œ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด๋‹ค.

์ด๊ฑธ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋™๊ธฐํ™” ๊ฐœ๋…๋“ค์„ ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค.
์‚ฌ์‹ค ์ด์— ๋Œ€ํ•œ ๊ฐ€์žฅ ๊ฐ„ํŽธํ•œ ํ•ด๊ฒฐ์ฑ…์€ ์ฑ„๋„์ด๋‹ค.
https://blog.naver.com/sssang97/223176685609
ํ•˜์ง€๋งŒ ์ฑ„๋„์€ ์ˆ˜์‹ ์ž์™€ ์†ก์‹ ์ž๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„๋˜๋Š” ์ผ€์ด์Šค์—๋งŒ ์ ํ•ฉํ•˜๊ณ , ๊ฐ ์Šค๋ ˆ๋“œ๋“ค์ด ์ฝ๊ธฐ/์“ฐ๊ธฐ๋ฅผ ๋Šฅ๋™์ ์œผ๋กœ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ๊ณค๋ž€ํ•˜๋‹ค. ์ด๋Ÿด ๋•Œ๋Š” ์ง์ ‘ ๋ฝ์„ ๊ฑธ๊ฑฐ๋‚˜ ํ•ด์•ผ ํ•œ๋‹ค.





Mutex

Mutex๋Š” ์–ธ์–ด๋ฅผ ์ดˆ์›”ํ•ด์„œ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋™๊ธฐํ™” ๊ธฐ์ˆ ์ด๋‹ค.
https://blog.naver.com/sssang97/223131650074

๊ทธ๋ƒฅ ๋ฌด์‹ํ•˜๊ฒŒ ๋ฝ๊ฑธ๊ณ  ๋‹ค๋ฅธ๋†ˆ์ด ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๋Š”๊ฒŒ ๋‹ค๋‹ค.
๊ฐ„๋‹จํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๋„ˆ๋ฌด ๋‚จ๋ฐœํ•˜๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ์‹ฌํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฐ๋“œ๋ฝ์˜ ๋ฌธ์ œ๋„ ํ•ญ์ƒ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ์—์„œ๋Š” mutex๋ฅผ ์ ์šฉํ•ด์„œ data race๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.

์šฐ์„  ๋ฎคํ…์Šคํ‹€ ๊ณต์œ ์šฉ์œผ๋กœ ์„ ์–ธํ•œ ๋‹ค์Œ์—

์“ฐ๊ธฐ๋ฅผ ํ• ๋•Œ๋งˆ๋‹ค ๋ฝ์„ ๊ฑธ๊ณ  ํ’€๋„๋ก ํ–ˆ๋‹ค.

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	var shared = 0
	var mutex = sync.Mutex{} // ๊ณต์œ ๋ณ€์ˆ˜๋ฅผ ๋ณดํ˜ธํ•  ๋ฎคํ…์Šค ์ƒ์„ฑ

	// ๊ณ ๋ฃจํ‹ด 10๊ฐœ ๋„์šฐ๊ธฐ
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			// ๊ฐ ๊ณ ๋ฃจํ‹ด์€ ๊ณต์œ ๋ณ€์ˆ˜๋ฅผ 10000๋ฒˆ์”ฉ ์ฆ๊ฐ€์‹œํ‚ด
			for j := 0; j < 10000; j++ {
				mutex.Lock() // ๊ณต์œ ๋ณ€์ˆ˜ ๋ณดํ˜ธ ์‹œ์ž‘
				shared++
				mutex.Unlock() // ๊ณต์œ ๋ณ€์ˆ˜ ๋ณดํ˜ธ ์ข…๋ฃŒ
			}
		}()
	}

	wg.Wait()
	fmt.Println(shared) // 10 * 10000 = 100000๊ฐ€ ๋‚˜์™€์•ผ ํ•˜๋Š”๋ฐ...?
}

๊ทธ๋Ÿผ ์•ฝ๊ฐ„ ๋А๋ ค์ง€๊ธด ํ•˜์ง€๋งŒ ์˜๋„๋Œ€๋กœ ๋™์ž‘์€ ํ•œ๋‹ค.




atomic

mutex lock์œผ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ๋ณ‘๋ชฉ์ด ์‹ฌ๊ฐํ•˜๊ฒŒ ์šฐ๋ ค๋  ๊ฒฝ์šฐ์—๋Š”, atomic ๊ธฐ๋Šฅ๋“ค์„ ์‘์šฉํ•˜๋Š”๊ฒŒ ์ข‹์„ ์ˆ˜ ์žˆ๋‹ค.
์ด๊ฑด ๋ฌด์‹ํ•˜๊ฒŒ ๋ฝ์„ ๊ฑฐ๋Š”๊ฒŒ ์•„๋‹ˆ๊ณ , CPU ์ธ์ŠคํŠธ๋Ÿญ์…˜ ์ˆ˜์ค€์—์„œ ์ œ๊ณตํ•˜๋Š” ํŠน์ • ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•ด์„œ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค.

๋‚ด๊ฐ€ ์•Œ๊ธฐ๋กœ ๋‚ด์žฅ atomic ๊ธฐ๋Šฅ์€ Compare And Swap์„ ๊ธฐ๋ฐ˜์œผ๋กœ atomic์„ ์ œ๊ณตํ•œ๋‹ค. ํ™•์‹คํ•˜์ง€๋Š” ์•Š๋‹ค.
https://blog.naver.com/sssang97/222721792446

์•„๋ž˜์—์„œ๋Š” atomic์„ ํ™œ์šฉํ•ด์„œ data race๋ฅผ ์ œ๊ฑฐํ•ด๋ดค๋‹ค.

๊ทธ๋ƒฅ ๋ง์…ˆ์ด๋ž€ ํ–‰์œ„ ์ž์ฒด๋ฅผ atomic operation์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	var wg sync.WaitGroup
	var shared int32 = 0

	// ๊ณ ๋ฃจํ‹ด 10๊ฐœ ๋„์šฐ๊ธฐ
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			// ๊ฐ ๊ณ ๋ฃจํ‹ด์€ ๊ณต์œ ๋ณ€์ˆ˜๋ฅผ 10000๋ฒˆ์”ฉ ์ฆ๊ฐ€์‹œํ‚ด
			for j := 0; j < 10000; j++ {
				atomic.AddInt32(&shared, 1)
			}
		}()
	}

	wg.Wait()
	fmt.Println(shared) // 10 * 10000 = 100000๊ฐ€ ๋‚˜์™€์•ผ ํ•˜๋Š”๋ฐ...?
}

๊ทธ๋Ÿผ ๊ธฐ๋Œ€ํ•˜๋˜๋Œ€๋กœ ๋น ๋ฅด๊ฒŒ๋„ ๋‚˜์˜ค๊ณ , ์„ฑ๋Šฅ๋„ ์ถฉ๋ถ„ํžˆ ๋‚˜์˜ฌ ๊ฒƒ์ด๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” ๊ทธ๋ƒฅ ์“ฐ๊ธฐ๋งŒ ๋ฌด์‹ํ•˜๊ฒŒ ํ•ด์„œ atomic์ด ์ข‹์•„๋ณด์ผ ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ํƒ€์ž…์ด ๋ณต์žกํ•˜๊ฑฐ๋‚˜ ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ, ๊ฒ€์ฆ ๋“ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” atomic์œผ๋กœ๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค.



์ฐธ์กฐ
https://pkg.go.dev/sync/atomic
https://ikcoo.tistory.com/m/214