Κατά τη συγγραφή εφαρμογών πολλαπλών νημάτων, ένα από τα πιο συνηθισμένα προβλήματα που παρουσιάζονται είναι οι συνθήκες ανταγωνισμού.
Τα ερωτήματά μου προς την κοινότητα είναι τα εξής:
Τι είναι η συνθήκη αγώνα; Πώς τις εντοπίζετε; Πώς τις χειρίζεστε; Τέλος, πώς αποτρέπετε την εμφάνισή τους;
Μια κατάσταση αγώνα συμβαίνει όταν δύο ή περισσότερα νήματα έχουν πρόσβαση σε κοινά δεδομένα και προσπαθούν να τα αλλάξουν ταυτόχρονα. Επειδή ο αλγόριθμος χρονοπρογραμματισμού νημάτων μπορεί να κάνει εναλλαγή μεταξύ νημάτων ανά πάσα στιγμή, δεν γνωρίζετε τη σειρά με την οποία τα νήματα θα προσπαθήσουν να αποκτήσουν πρόσβαση στα κοινά δεδομένα. Επομένως, το αποτέλεσμα της αλλαγής των δεδομένων εξαρτάται από τον αλγόριθμο χρονοπρογραμματισμού νημάτων, δηλαδή και τα δύο νήματα "αγωνίζονται"- για να προσπελάσουν/αλλάξουν τα δεδομένα.
Προβλήματα εμφανίζονται συχνά όταν ένα νήμα κάνει ένα "check-then-act" (π.χ. "check" αν η τιμή είναι X, στη συνέχεια "act" για να κάνει κάτι που εξαρτάται από το αν η τιμή είναι X) και ένα άλλο νήμα κάνει κάτι στην τιμή μεταξύ του "check" και του "act". Π.χ:
if (x == 5) // The "Check"
{
y = x * 2; // The "Act"
// If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
// y will not be equal to 10.
}
Το θέμα είναι ότι το y θα μπορούσε να είναι 10, ή θα μπορούσε να είναι οτιδήποτε, ανάλογα με το αν ένα άλλο νήμα άλλαξε το x μεταξύ του ελέγχου και της πράξης. Δεν έχετε πραγματικό τρόπο να το ξέρετε.
Προκειμένου να αποτρέψετε την εμφάνιση συνθηκών ανταγωνισμού, θα βάζατε συνήθως ένα κλείδωμα γύρω από τα κοινόχρηστα δεδομένα για να διασφαλίσετε ότι μόνο ένα νήμα μπορεί να έχει πρόσβαση στα δεδομένα κάθε φορά. Αυτό θα σήμαινε κάτι τέτοιο:
// Obtain lock for x
if (x == 5)
{
y = x * 2; // Now, nothing can change x until the lock is released.
// Therefore y = 10
}
// release lock for x
Μια συνθήκη αγώνα είναι ένα είδος σφάλματος, το οποίο συμβαίνει μόνο με ορισμένες χρονικές συνθήκες.
Παράδειγμα: Φανταστείτε ότι έχετε δύο νήματα, το Α και το Β.
Στο νήμα Α: