Skip to content
Santekno.com | Tech Tutorials and Trends
ID
📖 0%
17 Jun 2023 · 5 mnt baca ·Artikel 104 / 119
Go

Mengenal Deadlock Dan Cara Mengatasinya Pada Golang

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Pengenalan

Salah satu masalah yang terjadi ketika menggunakan concurrent atau paralel yaitu sistem deadlock. Apa itu deadlock? Deadlock adalah kejadian dimana sebuah proses concurrent atau goroutine saling menunggu (lock) sehingga tidak ada satupun goroutine yang bisa berjalan. Maka hati-hati bagi Anda jika membuat aplikasi atau program yang mengimplementasikan mutex lock and unlock dengan menggunakan goroutine. Baiklah kita akan coba saja langsung bagaimana simulasi pada program golang ketika terjadi deadlock.

Pembuatan Mutex Lock And Lock

Pertama kali kita coba buat struct untuk menampung hitungan data dengan menggungakan struct dan beberapa fungsi lock and unlock. Dan jangan lupa juga kita akan mensimulasikan ini dengan penggunaan Mutex. Berikut kode yang harus pertama kali kamu buat dibawah ini.

go
 1type UserCount struct {
 2	Name       string
 3	TotalCount int
 4	sync.Mutex
 5}
 6
 7func (c *UserCount) Lock() {
 8	c.Mutex.Lock()
 9}
10
11func (c *UserCount) Unlock() {
12	c.Mutex.Unlock()
13}
14
15func (c *UserCount) Change(amount int) {
16	c.TotalCount = c.TotalCount + amount
17}

Membuat Fungsi TransferPoint

Pada fungsi TransferPoint ini kita akan mensimulasikan bahwa User satu akan melakukan transfer terhadap User yang lain sehingga nanti kita juga buat agar terjadi deadlock.

go
 1func TransferPoint(user1 *UserCount, user2 *UserCount, amount int) {
 2	user1.Lock()
 3	fmt.Println("Lock processing for user : ", user1.Name)
 4	user1.Change(-amount)
 5
 6	time.Sleep(1 * time.Second)
 7
 8	user2.Lock()
 9	fmt.Println("Lock processing for user : ", user2.Name)
10	user2.Change(amount)
11
12	time.Sleep(1 * time.Second)
13
14	user1.Unlock()
15	user2.Unlock()
16}

Selanjutnya kita akan membuat main() fungsi yang akan menjalankan simulasinya lebih lengkap seperti dibawah ini.

go
 1func main() {
 2	user1 := UserCount{
 3		Name:       "Ihsan",
 4		TotalCount: 100,
 5	}
 6
 7	user2 := UserCount{
 8		Name:       "Arif",
 9		TotalCount: 100,
10	}
11
12  // call TransferPoint
13
14	fmt.Printf("User: %s count: %d\n", user1.Name, user1.TotalCount)
15	fmt.Printf("User: %s count: %d\n", user2.Name, user2.TotalCount)
16
17}
Lalu, jalankan proses main tersebut sehingga akan mengeluarkan seperti dibawah ini.
go
1User: Ihsan count: 100
2User: Arif count: 100

Percobaan Pertama Memanggil tanpa Goroutine

Pada percobaan 1, kita akan melakukan simulasi memanggil fungsi TransferPoint tanpa Goroutine seharusnya ini akan aman-aman saja dan tidak akan terjadi deadlock. Kenapa bisa begitu? karena fungsi TransferPoint ini tidak dipanggil dalam waktu yang bersamaan. Baik, Anda coba tambahkan atau panggil fungsi TransferPoint setelah inisialisasi user seperti ini.

go
1TransferPoint(&user1, &user2, 10)
2TransferPoint(&user2, &user1, 5)
Maka, hasilnya akan seperti ini
bash
1Lock processing for user :  Ihsan
2Lock processing for user :  Arif
3Lock processing for user :  Arif
4Lock processing for user :  Ihsan
5User: Ihsan count: 95
6User: Arif count: 105
User Ihsan dan Arif memiliki point yang sama yaitu 100, lalu mereka saling transfer point yang mana sebagai berikut:

  • Ihsan akan melakukan transfer point 10 kepada user Arif
  • Arif akan melakukan transfer point 5 kepada user Ihsan Maka, perhitungan total count-nya masing-masing itu akan seperti ini:
  • Ihsan = 100 - 10 (sent) + 5 (receive) = 95
  • Arif = 100 - 5 (sent) + 10 (receive) = 105

Hasil perhitungan ini adalah benar

Percobaan Dua Memanggil menggunakan Goroutine

Pada percobaan 2, kita coba simulasikan kembali yang mana ini akan terjadi deadlock saat pemanggilan fungsi TransferPoint itu berjalan menggunakan goroutine. Baik, Anda coba tambahkan paling dari fungsi tersebut dengan go dan juga tambahkan time.Sleep agar proses goroutine yang sedang berjalan akan kita tunggu selama 3 detik, maka lihat kode dibawah ini.

go
1go TransferPoint(&user1, &user2, 10)
2go TransferPoint(&user2, &user1, 5)
3
4time.Sleep(3 * time.Second)
Maka apa yang akan terjadi hasil program ketika dijalankan?
bash
1Lock processing for user :  Ihsan
2Lock processing for user :  Arif
3User: Ihsan count: 90
4User: Arif count: 95
Perhitungan dari fungsi tersebut menjadi salah dan kenapa ini terjadi yaitu karena deadlock. Baik kita coba bedah kenapa perhitungannya berbeda.

  • Saat User Ihsan melakukan transfer maka terjadi lock terhadap user Ihsan.
  • Disaat waktu yang bersamaan User Arif juga akan melakukan transfer maka terjadi lock terhadap User Arif.
  • Ketika User Ihsan akan melanjutkan proses menambahkan amount kepada Arif, ternyata user Arif dalam keadaan masih lock sehingga proses tersebut ditunggu.
  • Begitu juga sebaliknya User Arif juga akan melanjutkan proses menambahkan amount terhadap Ihsan tetapi ternyata user Ihsan masih lock sehingga menunggu juga.
  • Maka, disinilah terjadi deadlock yang mana kedua proses tersebut saling menunggu sampai waktu yg tidak ditentukan.
  • Pada program ini kita ditentukan dalam waktu 3 detik, maka proses-nya pun berhenti dan perhitungannya akan menjadi salah atau kacau.

Solusi Deadlock

Setelah kita tahu bagaimana proses deadlock itu terjadi maka, bagaimana solusinya agar tidak terjadi seperti itu yaitu dengan cara melakukan Unlock setiap ada perubahan data dari user tersebut. Maka, kita akan ubah fungsi TransferPoint seperti dibawah ini.

go
 1func TransferPoint(user1 *UserCount, user2 *UserCount, amount int) {
 2	user1.Lock()
 3	fmt.Println("Lock processing for user : ", user1.Name)
 4	user1.Change(-amount)
 5	user1.Unlock()
 6
 7	time.Sleep(1 * time.Second)
 8
 9	user2.Lock()
10	fmt.Println("Lock processing for user : ", user2.Name)
11	user2.Change(amount)
12	user2.Unlock()
13
14	time.Sleep(1 * time.Second)
15}
Saat dijalankan program tersebut akan menghasilkan keluaran yang sama dengan yang percobaan 1.
bash
1Lock processing for user :  Arif
2Lock processing for user :  Ihsan
3Lock processing for user :  Arif
4Lock processing for user :  Ihsan
5User: Ihsan count: 95
6User: Arif count: 105

Artikel Terkait

💬 Komentar