Menu
CoddyTech

sync.Mutex & sync.RWMutex

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 63 dari 107.

Meskipun channel adalah cara yang diutamakan di Go untuk mengoordinasikan goroutine, terkadang kamu perlu melindungi data bersama secara langsung. Package sync menyediakan mutex: pengunci yang memastikan hanya satu goroutine yang mengakses sumber daya pada satu waktu.

Sebuah sync.Mutex memiliki dua method: Lock() dan Unlock(). Saat sebuah goroutine memanggil Lock(), goroutine itu mendapat akses eksklusif. Goroutine lain yang memanggil Lock() akan terblokir hingga Unlock() dipanggil:

type Counter struct {
    mu    sync.Mutex
    value int
}
func (c *Counter) Increment() {
    c.mu.Lock()
    c.value++
    c.mu.Unlock()
}
func (c *Counter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.value
}

Menggunakan defer c.mu.Unlock() memastikan kunci dilepas meskipun fungsi mengembalikan nilai lebih awal atau mengalami panic: pola yang umum dan direkomendasikan.

Saat pembacaan sering dilakukan tetapi penulisan jarang, sync.RWMutex menawarkan kinerja yang lebih baik. Ini memungkinkan beberapa pembaca mengakses secara bersamaan, tetapi penulis mendapat akses eksklusif:

type Cache struct {
    mu   sync.RWMutex
    data map[string]string
}
func (c *Cache) Get(key string) string {
    c.mu.RLock()         // beberapa pembaca dapat mengakses secara bersamaan
    defer c.mu.RUnlock()
    return c.data[key]
}
func (c *Cache) Set(key, value string) {
    c.mu.Lock()          // akses eksklusif untuk menulis
    defer c.mu.Unlock()
    c.data[key] = value
}

Gunakan RLock()/RUnlock() untuk operasi baca dan Lock()/Unlock() untuk operasi tulis. Ini memungkinkan pembacaan dilakukan secara bersamaan sekaligus memastikan penulisan aman.

challenge icon

Tantangan

Mudah

Mari kita membangun sistem inventaris aman untuk konkurensi yang melacak tingkat stok produk. Sistemmu akan menangani pembacaan dan penulisan secara bersamaan dengan aman menggunakan mutex, sehingga integritas data tetap terjaga saat beberapa operasi berlangsung secara bersamaan.

Kamu akan mengatur kodemu dalam dua file:

  • inventory.go: Definisikan sistem manajemen inventaris aman untuk konkurensi.

    Buat struct Inventory yang menyimpan jumlah produk dalam map dan menggunakan sync.RWMutex untuk melindungi akses. Inventarismu harus mendukung operasi berikut:

    • NewInventory() *Inventory : Membuat inventaris baru dengan map yang sudah diinisialisasi
    • AddStock(product string, quantity int) : Menambahkan jumlah ke stok produk. Gunakan kunci eksklusif karena operasi ini mengubah data
    • GetStock(product string) int : Mengembalikan stok produk saat ini, atau 0 jika tidak ditemukan. Gunakan kunci baca karena operasi ini hanya membaca data
    • RemoveStock(product string, quantity int) bool : Mengurangi jumlah dari stok jika stok mencukupi. Mengembalikan true jika berhasil, false jika stok tidak mencukupi. Gunakan kunci eksklusif

    Ingatlah untuk menggunakan defer saat membuka kunci agar kunci selalu dilepas dengan benar.

  • main.go: Baca operasi dan tunjukkan cara kerja inventaris aman untuk konkurensi.

    Baca jumlah operasi, lalu proses setiap operasi. Setiap operasi memiliki tipe (add, get, atau remove), nama produk, dan, untuk operasi add/remove, jumlahnya.

    Untuk setiap operasi, cetak hasilnya:

    • add: Cetak Added [quantity] [product]
    • get: Cetak [product]: [stock] in stock
    • remove: Cetak Removed [quantity] [product] jika berhasil, atau Insufficient stock for [product] jika tidak

Input berikut akan diberikan:

  • Baris 1: Jumlah operasi (bilangan bulat)
  • Baris-baris berikutnya: Untuk setiap operasi:
    • Tipe operasi (add, get, atau remove)
    • Nama produk
    • Jumlah (hanya untuk operasi add dan remove)

Contohnya, jika diberikan:

5
add
apples
50
get
apples
remove
apples
30
remove
apples
25
get
apples

Outputmu seharusnya:

Added 50 apples
apples: 50 in stock
Removed 30 apples
Insufficient stock for apples
apples: 20 in stock

RWMutex memungkinkan beberapa pemanggilan GetStock membaca secara bersamaan, sedangkan AddStock dan RemoveStock mendapatkan akses eksklusif saat mengubah inventaris.

Coba sendiri

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Baca jumlah operasi
	line, _ := reader.ReadString('\n')
	numOps, _ := strconv.Atoi(strings.TrimSpace(line))
	
	// Buat inventaris baru
	inventory := NewInventory()
	
	// Proses setiap operasi
	for i := 0; i < numOps; i++ {
		// Baca jenis operasi
		opLine, _ := reader.ReadString('\n')
		opType := strings.TrimSpace(opLine)
		
		// Baca nama produk
		productLine, _ := reader.ReadString('\n')
		product := strings.TrimSpace(productLine)
		
		// TODO: Tangani setiap jenis operasi (add, get, remove)
		// Untuk "add" dan "remove", baca jumlah dari input
		// Panggil method inventaris yang sesuai
		// Cetak hasil sesuai deskripsi tantangan
		
		switch opType {
		case "add":
			// TODO: Baca jumlah, tambahkan stok, cetak hasil
			
		case "get":
			// TODO: Ambil stok, cetak hasil
			
		case "remove":
			// TODO: Baca jumlah, kurangi stok, cetak hasil yang sesuai
			
		}
	}
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Go online