Τι είναι ένα mutex, ποιοι τύποι mutex υπάρχουν και πώς τα χρησιμοποιούμε;
sobes.tech AI
Απάντηση από AI
Ο αμοιβαίος αποκλεισμός (από τα αγγλικά MUTual EXclusion) είναι μια primitive συγχρονισμού που χρησιμοποιείται για την εξασφάλιση αποκλειστικής πρόσβασης σε κοινόχρηστο πόρο μεταξύ ανταγωνιστικών goroutines. Διασφαλίζει ότι σε κάθε χρονική στιγμή μόνο μια goroutine μπορεί να κατέχει τον αμοιβαίο αποκλεισμό και να έχει πρόσβαση στα προστατευόμενα δεδομένα.
Στο Go, το πακέτο sync παρέχει δύο βασικούς τύπους mutex:
-
sync.Mutex: Τυπικός mutex. Παρέχει τις μεθόδουςLock()καιUnlock(). Αν ο mutex ήδη είναι κλειδωμένος, η κλήσηLock()μπλοκάρει την τρέχουσα goroutine μέχρι να απελευθερωθεί. ΤοUnlock()ξεκλειδώνει τον mutex.var mu sync.Mutex var counter int func increment() { mu.Lock() // Κλειδώνει την πρόσβαση στο counter counter++ mu.Unlock() // Ξεκλειδώνει την πρόσβαση } -
sync.RWMutex: Mutex για ανάγνωση/εγγραφή. Επιτρέπει σε πολλαπλές goroutines να διαβάζουν ταυτόχρονα τον προστατευόμενο πόρο, αλλά μόνο μία να γράφει. Παρέχει τις μεθόδουςLock(),Unlock()(για εγγραφή),RLock()καιRUnlock()(για ανάγνωση).var rwMu sync.RWMutex var data []int func readData() { rwMu.RLock() // Κλειδώνει για ανάγνωση // Ανάγνωση data fmt.Println(data) rwMu.RUnlock() // Ξεκλειδώνει την ανάγνωση } func writeData(val int) { rwMu.Lock() // Κλειδώνει για εγγραφή // Εγγραφή σε data data = append(data, val) rwMu.Unlock() // Ξεκλειδώνει την εγγραφή }
Η χρήση mutex είναι απαραίτητη για την αποτροπή καταστάσεων αγώνα (race conditions), όταν πολλές goroutines προσπαθούν ταυτόχρονα να τροποποιήσουν τα ίδια δεδομένα, οδηγώντας σε απρόβλεπτα αποτελέσματα.
Κανόνες χρήσης:
- Καλείτε
Lock()πριν την πρόσβαση στον προστατευόμενο πόρο. - Καλείτε
Unlock()μετά το τέλος της πρόσβασης. Συνιστάται η χρήσηdefer mu.Unlock()για την εγγύηση της απελευθέρωσης ακόμα και σε περίπτωση πανικού. - Μην προσπαθείτε να κλειδώσετε ήδη κλειδωμένο mutex από την ίδια goroutine (μπορεί να οδηγήσει σε deadlock).
- Μην προσπαθείτε να ξεκλειδώσετε ένα μη κλειδωμένο mutex.
- Κατά τη χρήση
RWMutex, χρησιμοποιείτεRLock/RUnlockγια αναγνώσεις καιLock/Unlockγια εγγραφές. - Τα mutex δεν πρέπει να αντιγράφονται μετά την πρώτη χρήση. Τα περνάτε μέσω αναφοράς ή δείκτη.
Παράδειγμα χρήσης defer:
func safeIncrement() {
mu.Lock()
defer mu.Unlock() // Εγγυάται την απελευθέρωση
counter++
}