DEV Community

ynwd
ynwd

Posted on

2 2

Data Races di Golang: Fixing with Mutex

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())
}

Enter fullscreen mode Exit fullscreen mode

Kalau dilihat secara sequence diagram, ia mirip dengan kode sebelumnya.

  • Go routine #1 : main()
  • Go routine #2 : fungsi di mana i.Set() dipanggil.

data races

Dan jika kita jalankan dengan -race:

go run -race main.go  
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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())
}

Enter fullscreen mode Exit fullscreen mode

Jika kita jalankan dengan -race, hasilnya:

$ go run -race main.go                                                     main*
hi
Enter fullscreen mode Exit fullscreen mode

mutex prevent datarace

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.

Diagram data races

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay