Sebelumnya, kita telah membahas data race di golang dan channel. Sekarang kita akan mencoba memperbaiki data races dengan mutex.
Tapi sebelumnya, kita akan menambahkan sebuah struct text
serta getter-setter-nya dan mengubah fungsi getText()
, menjadi seperti ini:
package main
import (
"fmt"
)
func getText() string {
i := text{txt: "hi"}
go func() {
i.Set("hello")
}()
return i.Get()
}
type text struct {
txt string
}
func (t *text) Set(txt string) {
t.txt = txt
}
func (t *text) Get() string {
return t.txt
}
func main() {
fmt.Println(getText())
}
Kalau dilihat secara sequence diagram, ia mirip dengan kode sebelumnya.
- Go routine #1 :
main()
- Go routine #2 : fungsi di mana
i.Set()
dipanggil.
Dan jika kita jalankan dengan -race
:
go run -race main.go
Maka ia juga akan menghasilkan warning:
hi
==================
WARNING: DATA RACE
Write at 0x00c000012230 by goroutine 7:
main.(*text).Set()
/Users/pro/Documents/apps/cms/cmd/main.go:20 +0x33
main.getText.func1()
/Users/pro/Documents/apps/cms/cmd/main.go:10 +0x2e
Previous read at 0x00c000012230 by main goroutine:
main.(*text).Get()
/Users/pro/Documents/apps/cms/cmd/main.go:24 +0xda
main.getText()
/Users/pro/Documents/apps/cms/cmd/main.go:12 +0xf1
main.main()
/Users/pro/Documents/apps/cms/cmd/main.go:28 +0x24
Goroutine 7 (running) created at:
main.getText()
/Users/pro/Documents/apps/cms/cmd/main.go:9 +0xd0
main.main()
/Users/pro/Documents/apps/cms/cmd/main.go:28 +0x24
==================
Found 1 data race(s)
exit status 66
Solusi dengan mutex
Mutex gunanya untuk mencegah agar sebuah variabel tidak diakses secara bersamaan.
Implementasinya sangat mudah. Kita tinggal menempatkan saja method Lock
dan Unlock
di variabel yang terkena data races.
package main
import (
"fmt"
"sync"
)
func getText() string {
i := text{txt: "hi"}
go func() {
i.Set("hello")
}()
return i.Get()
}
type text struct {
txt string
mutex sync.Mutex
}
func (t *text) Set(txt string) {
t.mutex.Lock()
defer t.mutex.Unlock()
t.txt = txt
}
func (t *text) Get() string {
t.mutex.Lock()
defer t.mutex.Unlock()
return t.txt
}
func main() {
fmt.Println(getText())
}
Jika kita jalankan dengan -race
, hasilnya:
$ go run -race main.go main*
hi
Yang menjadi pertanyaan: mengapa hasilnya tetap hi
?
Jawabannya adalah: karena go routine #1 (main), selesainya lebih dulu dan langsung exit.
Walaupun go routine ke-2 sedang berjalan, karena go routine #1 sudah exit duluan, ya sudah, program selesai.
Top comments (0)