Προγραμματισμός

Πότε να χρησιμοποιήσετε την ευμετάβλητη λέξη-κλειδί στο C #

Οι τεχνικές βελτιστοποίησης που χρησιμοποιούνται από τον μεταγλωττιστή JIT (just-in-time) στο Common Language Runtime ενδέχεται να οδηγήσουν σε απρόβλεπτα αποτελέσματα όταν το .Net πρόγραμμα προσπαθεί να εκτελέσει μη πτητικές αναγνώσεις δεδομένων σε ένα σενάριο πολλαπλών νημάτων. Σε αυτό το άρθρο θα εξετάσουμε τις διαφορές μεταξύ της πτητικής και της μη πτητικής πρόσβασης στη μνήμη, του ρόλου της πτητικής λέξης-κλειδιού στο C # και του τρόπου με τον οποίο πρέπει να χρησιμοποιείται η πτητική λέξη-κλειδί.

Θα δώσω μερικά παραδείγματα κώδικα στο C # για να δείξω τις έννοιες. Για να κατανοήσουμε πώς λειτουργεί η πτητική λέξη-κλειδί, πρώτα πρέπει να καταλάβουμε πώς λειτουργεί η στρατηγική βελτιστοποίησης μεταγλωττιστή JIT στο .Net.

Κατανόηση των βελτιστοποιήσεων μεταγλωττιστή JIT

Θα πρέπει να σημειωθεί ότι ο μεταγλωττιστής JIT, ως μέρος μιας στρατηγικής βελτιστοποίησης, θα αλλάξει τη σειρά των αναγνώσεων και των εγγραφών με τρόπο που δεν αλλάζει τη σημασία και την τελική έξοδο του προγράμματος. Αυτό απεικονίζεται στο απόσπασμα κώδικα που δίνεται παρακάτω.

x = 0;

x = 1;

Το παραπάνω απόσπασμα κώδικα μπορεί να αλλάξει ως εξής - διατηρώντας παράλληλα την αρχική σημασιολογία του προγράμματος.

x = 1;

Ο μεταγλωττιστής JIT μπορεί επίσης να εφαρμόσει μια ιδέα που ονομάζεται «συνεχής διάδοση» για τη βελτιστοποίηση του ακόλουθου κώδικα.

x = 1;

y = x;

Το παραπάνω απόσπασμα κώδικα μπορεί να αλλάξει στα ακόλουθα - και πάλι διατηρώντας την αρχική σημασιολογία του προγράμματος.

x = 1;

y = 1;

Πρόσβαση σε πτητική έναντι μη πτητικής μνήμης

Το μοντέλο μνήμης των σύγχρονων συστημάτων είναι αρκετά περίπλοκο. Έχετε καταχωρητές επεξεργαστών, διάφορα επίπεδα προσωρινής μνήμης και κύρια μνήμη που μοιράζονται πολλοί επεξεργαστές. Όταν το πρόγραμμά σας εκτελείται, ο επεξεργαστής ενδέχεται να αποθηκεύσει προσωρινά τα δεδομένα και στη συνέχεια να αποκτήσει πρόσβαση σε αυτά τα δεδομένα από την προσωρινή μνήμη όταν ζητηθεί από το νήμα εκτέλεσης. Οι ενημερώσεις και οι αναγνώσεις αυτών των δεδομένων ενδέχεται να εκτελούνται έναντι της προσωρινής αποθήκευσης των δεδομένων, ενώ η κύρια μνήμη ενημερώνεται αργότερα. Αυτό το μοντέλο χρήσης μνήμης έχει συνέπειες για εφαρμογές πολλαπλών νημάτων.

Όταν ένα νήμα αλληλεπιδρά με τα δεδομένα στην προσωρινή μνήμη και ένα δεύτερο νήμα προσπαθεί να διαβάσει τα ίδια δεδομένα ταυτόχρονα, το δεύτερο νήμα μπορεί να διαβάσει μια παλιά έκδοση των δεδομένων από την κύρια μνήμη. Αυτό συμβαίνει επειδή όταν ενημερώνεται η τιμή ενός μη πτητικού αντικειμένου, η αλλαγή πραγματοποιείται στην προσωρινή μνήμη του νήματος εκτέλεσης και όχι στην κύρια μνήμη. Ωστόσο, όταν ενημερώνεται η τιμή ενός πτητικού αντικειμένου, δεν γίνεται μόνο η αλλαγή στην προσωρινή μνήμη του νήματος εκτέλεσης, αλλά αυτή η προσωρινή μνήμη μεταφέρεται στη βασική μνήμη. Και όταν διαβάζεται η τιμή ενός πτητικού αντικειμένου, το νήμα ανανεώνει την προσωρινή μνήμη του και διαβάζει την ενημερωμένη τιμή.

Χρήση της ευμετάβλητης λέξης-κλειδιού στο C #

Η πτητική λέξη-κλειδί στο C # χρησιμοποιείται για να ενημερώσει τον μεταγλωττιστή JIT ότι η τιμή της μεταβλητής δεν θα πρέπει ποτέ να αποθηκευτεί προσωρινά στην κρυφή μνήμη, επειδή μπορεί να αλλάξει από το λειτουργικό σύστημα, το υλικό ή ένα νήμα που εκτελεί ταυτόχρονα. Έτσι, ο μεταγλωττιστής αποφεύγει τη χρήση βελτιστοποιήσεων στη μεταβλητή που ενδέχεται να οδηγήσουν σε διενέξεις δεδομένων, δηλαδή σε διαφορετικά νήματα που έχουν πρόσβαση σε διαφορετικές τιμές της μεταβλητής.

Όταν επισημαίνετε ένα αντικείμενο ή μια μεταβλητή ως πτητική, γίνεται υποψήφιος για ασταθείς αναγνώσεις και εγγραφές. Θα πρέπει να σημειωθεί ότι στο C # όλες οι εγγραφές μνήμης είναι πτητικές ανεξάρτητα από το εάν γράφετε δεδομένα σε ένα πτητικό ή μη πτητικό αντικείμενο. Ωστόσο, η ασάφεια συμβαίνει όταν διαβάζετε δεδομένα. Όταν διαβάζετε δεδομένα που δεν είναι πτητικά, το νήμα εκτέλεσης μπορεί ή όχι να έχει πάντα την πιο πρόσφατη τιμή. Εάν το αντικείμενο είναι ασταθές, το νήμα παίρνει πάντα την πιο ενημερωμένη τιμή.

Μπορείτε να δηλώσετε μια μεταβλητή ως πτητική προτού την ακολουθήσετε με το πτητικός λέξη-κλειδί. Το ακόλουθο απόσπασμα κώδικα το δείχνει αυτό.

Πρόγραμμα τάξης

    {

δημόσια πτητική int i?

static void Main (συμβολοσειρά [] args)

        {

// Γράψτε τον κωδικό σας εδώ

        }

    }

Μπορείτε να χρησιμοποιήσετε το πτητικός λέξη-κλειδί με οποιονδήποτε τύπο αναφοράς, δείκτη και enum. Μπορείτε επίσης να χρησιμοποιήσετε τον πτητικό τροποποιητή με τύπους byte, short, int, char, float και bool. Πρέπει να σημειωθεί ότι οι τοπικές μεταβλητές δεν μπορούν να δηλωθούν ως πτητικές. Όταν καθορίζετε ένα αντικείμενο τύπου αναφοράς ως πτητικό, μόνο ο δείκτης (ένας ακέραιος 32-bit που δείχνει στη θέση στη μνήμη όπου το αντικείμενο είναι πραγματικά αποθηκευμένο) είναι πτητικό, όχι η τιμή της παρουσίας. Επίσης, μια διπλή μεταβλητή δεν μπορεί να είναι πτητική, επειδή έχει μέγεθος 64 bit, μεγαλύτερο από το μέγεθος λέξης σε συστήματα x86. Εάν πρέπει να κάνετε μια διπλή μεταβλητή πτητική, θα πρέπει να την τυλίξετε μέσα στην τάξη. Μπορείτε να το κάνετε εύκολα δημιουργώντας μια τάξη περιτυλίγματος, όπως φαίνεται στο παρακάτω απόσπασμα κώδικα.

δημόσια τάξη VolatileDoubleDemo

{

ιδιωτικό πτητικό WrappedVolatileDouble volatileData;

}

δημόσια τάξη WrappedVolatileDouble

{

δημόσια διπλά δεδομένα {get; σειρά; }

Ωστόσο, σημειώστε τον περιορισμό του παραπάνω παραδείγματος κώδικα. Αν και θα έχετε την τελευταία τιμή του πτητικά δεδομένα δείκτη αναφοράς, δεν είστε εγγυημένοι η τελευταία τιμή του Δεδομένα ιδιοκτησία. Το έργο γύρω από αυτό είναι να φτιάξουμε το WrappedVolatileDouble τύπος αμετάβλητος.

Παρόλο που η ευμετάβλητη λέξη-κλειδί μπορεί να σας βοηθήσει στην ασφάλεια του νήματος σε ορισμένες περιπτώσεις, δεν αποτελεί λύση σε όλα τα θέματα ταυτότητας νήματος. Πρέπει να γνωρίζετε ότι η επισήμανση μιας μεταβλητής ή ενός αντικειμένου ως ασταθούς δεν σημαίνει ότι δεν χρειάζεται να χρησιμοποιήσετε τη λέξη κλειδί κλειδώματος. Η ευμετάβλητη λέξη-κλειδί δεν αντικαθιστά τη λέξη κλειδί κλειδώματος. Είναι μόνο εκεί για να σας βοηθήσει να αποφύγετε διενέξεις δεδομένων όταν έχετε πολλά νήματα που προσπαθούν να αποκτήσουν πρόσβαση στα ίδια δεδομένα.