Αναγνώστες σαν εσάς βοηθούν στην υποστήριξη του MUO. Όταν κάνετε μια αγορά χρησιμοποιώντας συνδέσμους στον ιστότοπό μας, ενδέχεται να κερδίσουμε μια προμήθεια θυγατρικών. Διαβάστε περισσότερα.

Στο Linux, μπορείτε να δημιουργήσετε και να διαχειριστείτε νήματα σε C/C++ χρησιμοποιώντας τη βιβλιοθήκη νημάτων POSIX (pthread). Σε αντίθεση με άλλα λειτουργικά συστήματα, υπάρχει μικρή διαφορά μεταξύ ενός νήματος και μιας διαδικασίας στο Linux. Γι' αυτό το Linux συχνά αναφέρεται στα νήματα του ως διαδικασίες ελαφρού βάρους.

Χρησιμοποιώντας τη βιβλιοθήκη pthread, μπορείτε να δημιουργήσετε νήματα, να περιμένετε να τερματιστούν και να τα τερματίσετε ρητά.

Η ιστορία της χρήσης νημάτων στο Linux

Πριν από την έκδοση 2.6 του Linux, η κύρια εφαρμογή νήματος ήταν το LinuxThreads. Αυτή η υλοποίηση είχε σημαντικά όρια όσον αφορά την απόδοση και τις λειτουργίες συγχρονισμού. Ένα όριο στον μέγιστο αριθμό νημάτων που θα μπορούσαν να τρέξουν τα περιόριζε στα 1000s.

Το 2003, μια ομάδα με επικεφαλής προγραμματιστές της IBM και της RedHat πέτυχε την κατασκευή του

instagram viewer
Εγγενής βιβλιοθήκη νημάτων POSIX (NPTL) διαθέσιμο έργο. Παρουσιάστηκε για πρώτη φορά στην έκδοση 3 του RedHat Enterprise για την επίλυση προβλημάτων απόδοσης με την εικονική μηχανή Java στο Linux. Σήμερα, η βιβλιοθήκη GNU C περιέχει υλοποιήσεις και των δύο μηχανισμών νήματος.

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

Μπορείτε να βρείτε πληροφορίες σχετικά με το νήμα για οποιαδήποτε διεργασία που εκτελείται στα αρχεία παρακάτω /proc//task. Αυτή είναι η τυπική τοποθεσία για πληροφορίες διαδικασίας κάτω από το πρότυπο procfs Linux. Για εφαρμογές με ένα νήμα, θα φαίνεται ότι υπάρχει μια εγγραφή εργασιών με την ίδια τιμή με το PID σε αυτόν τον κατάλογο.

Λογική εργασίας των νημάτων

Τα νήματα είναι σαν διεργασίες που εκτελούνται αυτήν τη στιγμή στο λειτουργικό σύστημα. Σε συστήματα ενός επεξεργαστή (π.χ. μικροελεγκτές), ο πυρήνας του λειτουργικού συστήματος προσομοιώνει νήματα. Αυτό επιτρέπει στις συναλλαγές να εκτελούνται ταυτόχρονα μέσω τεμαχισμού.

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

Δημιουργία νήματος στο C

Μπορείτε να χρησιμοποιήσετε το pthread_create λειτουργία για τη δημιουργία νέου νήματος. ο pthread.h Το αρχείο κεφαλίδας περιλαμβάνει τον ορισμό της υπογραφής του μαζί με άλλες συναρτήσεις που σχετίζονται με το νήμα. Τα νήματα χρησιμοποιούν τον ίδιο χώρο διευθύνσεων και τους ίδιους περιγραφείς αρχείων με το κύριο πρόγραμμα.

Η βιβλιοθήκη pthread περιλαμβάνει επίσης την απαραίτητη υποστήριξη για λειτουργίες mutex και υπό όρους που απαιτούνται για λειτουργίες συγχρονισμού.

Όταν χρησιμοποιείτε τις λειτουργίες της βιβλιοθήκης pthread, πρέπει να βεβαιωθείτε ότι ο μεταγλωττιστής συνδέει το κλωστή βιβλιοθήκη στο εκτελέσιμό σας. Εάν είναι απαραίτητο, μπορείτε να δώσετε εντολή στον μεταγλωττιστή να συνδεθεί με τη βιβλιοθήκη χρησιμοποιώντας το -μεγάλο επιλογή:

gcc -ο δοκιμή test_thread.c -lpthread

Η συνάρτηση pthread_create έχει την ακόλουθη υπογραφή:

ενθpthread_create(pthread_t *Νήμα, συνθpthread_attr_t *attr, κενός *(*start_routine)(κενός *), κενός *arg)

Επιστρέφει 0 εάν η διαδικασία είναι επιτυχής. Εάν υπάρχει πρόβλημα, επιστρέφει έναν μη μηδενικό κωδικό σφάλματος. Στην παραπάνω υπογραφή λειτουργίας:

  • ο Νήμα η παράμετρος είναι τύπου pthread_t. Το νήμα που δημιουργήθηκε θα είναι πάντα προσβάσιμο με αυτήν την αναφορά.
  • ο attr Η παράμετρος σάς επιτρέπει να καθορίσετε προσαρμοσμένη συμπεριφορά. Μπορείτε να χρησιμοποιήσετε μια σειρά από συγκεκριμένες συναρτήσεις νήματος ξεκινώντας από pthread_attr_ για να ρυθμίσετε αυτήν την τιμή. Πιθανές προσαρμογές είναι η πολιτική προγραμματισμού, το μέγεθος στοίβας και η πολιτική αποσύνδεσης.
  • start_routine καθορίζει τη συνάρτηση που θα εκτελείται το νήμα.
  • αργ αντιπροσωπεύει μια γενική δομή δεδομένων που μεταβιβάζεται στη συνάρτηση από το νήμα.

Ακολουθεί ένα παράδειγμα εφαρμογής:

#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω

κενός *εργάτης(κενός *δεδομένα)
{
απανθρακώνω *όνομα = (απανθρακώνω*)δεδομένα;

Για (ενθ i = 0; i < 120; i++)
{
Κοιμάσαι(50000);
printf("Hi from thread name = %s\n", name);
}

printf("Το νήμα %s ολοκληρώθηκε!\n", όνομα);
ΕΠΙΣΤΡΟΦΗΜΗΔΕΝΙΚΟ;
}

ενθκύριος(κενός)
{
pthread_t th1, th2;
pthread_create(&th1, ΜΗΔΕΝΙΚΟ, εργαζόμενος, "Χ");
pthread_create(&th2, ΜΗΔΕΝΙΚΟ, εργαζόμενος, "Y");
ύπνος(5);
printf("Έξοδος από το κύριο πρόγραμμα\n");
ΕΠΙΣΤΡΟΦΗ0;
}

Τύποι νημάτων

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

Με την pthread_join αντ' αυτού μπορείτε να περιμένετε να τερματιστεί ένα νήμα. Το νήμα που χρησιμοποιεί αυτή τη συνάρτηση θα μπλοκάρει μέχρι να τερματιστεί το αναμενόμενο νήμα. Οι πόροι που χρησιμοποιούν από το σύστημα δεν επιστρέφονται ακόμη και σε περιπτώσεις όπως ο τερματισμός των συνδεόμενων νημάτων, ο μη προγραμματισμένος από την CPU ή ακόμη και η αποτυχία σύνδεσης με ptread_join.

Μερικές φορές υπάρχουν περιπτώσεις όπου η σύνδεση με το pthread_join δεν έχει νόημα. εάν είναι αδύνατο να προβλεφθεί πότε θα τελειώσει το νήμα, για παράδειγμα. Σε αυτήν την περίπτωση, μπορείτε να διασφαλίσετε ότι το σύστημα επιστρέφει αυτόματα όλους τους πόρους στο σημείο όπου επιστρέφει το νήμα.

Για να το πετύχετε αυτό, θα πρέπει να ξεκινήσετε τα σχετικά νήματα με το ΑΠΟΜΟΝΩΜΕΝΟΣ κατάσταση. Όταν ξεκινάτε ένα νήμα, ΑΠΟΣΠΩ Η κατάσταση μπορεί να οριστεί μέσω τιμών χαρακτηριστικών νήματος ή με το pthread_deach λειτουργία:

ενθpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ενθpthread_deach(pthread_t Νήμα);

Ακολουθεί ένα παράδειγμα χρήσης της pthread_join(). Αντικαταστήστε την κύρια λειτουργία στο πρώτο πρόγραμμα με την εξής:

ενθκύριος(κενός)
{
pthread_t th1, th2;
pthread_create(&th1, ΜΗΔΕΝΙΚΟ, εργαζόμενος, "Χ");
pthread_create(&th2, ΜΗΔΕΝΙΚΟ, εργαζόμενος, "Y");
ύπνος(5);
printf("έξοδος από το κύριο πρόγραμμα\n");
pthread_join (th1, ΜΗΔΕΝΙΚΟ);
pthread_join (th2, ΜΗΔΕΝΙΚΟ);
ΕΠΙΣΤΡΟΦΗ0;
}

Όταν κάνετε μεταγλώττιση και εκτέλεση του προγράμματος, η έξοδος θα είναι:

Γεια από το νήμα Υ
Γεια από το νήμα Χ
Γεια από το νήμα Υ
...
Γεια από το νήμα Υ
έξοδο από το κύριο πρόγραμμα
Γεια από το νήμα Χ
...
Γεια από το νήμα Χ
Το νήμα Χ έγινε!
Γεια από το νήμα Υ
Το νήμα Υ ολοκληρώθηκε!

Τερματισμός νήματος

Μπορείτε να ακυρώσετε ένα νήμα με μια κλήση στο pthread_cancel, περνώντας το αντίστοιχο pthread_t ταυτότητα:

ενθpthread_cancel(pthread_t Νήμα);

Μπορείτε να το δείτε σε δράση στον παρακάτω κώδικα. Και πάλι, μόνο το κύριος η λειτουργία είναι διαφορετική:

ενθκύριος(κενός)
{
pthread_t th1, th2;
pthread_create(&th1, ΜΗΔΕΝΙΚΟ, εργαζόμενος, "Χ");
pthread_create(&th2, ΜΗΔΕΝΙΚΟ, εργαζόμενος, "Y");
ύπνος(1);
printf("> Ακύρωση νήματος Y!!\n");
pthread_cancel (th2);
Κοιμάσαι(100000);
printf("> Ακύρωση νήματος X!\n");
pthread_cancel (th1);
printf("έξοδος από το κύριο πρόγραμμα\n");
ΕΠΙΣΤΡΟΦΗ0;
}

Γιατί δημιουργούνται νήματα;

Τα λειτουργικά συστήματα προσπαθούν πάντα να εκτελούν νήματα σε μία ή περισσότερες CPU, είτε από μια λίστα που έχει δημιουργηθεί μόνος του είτε από μια λίστα νημάτων που έχει δημιουργηθεί από τον χρήστη. Ορισμένα νήματα δεν μπορούν να τρέξουν επειδή περιμένουν ένα σήμα εισόδου/εξόδου από το υλικό. Μπορεί επίσης να περιμένουν οικειοθελώς, να περιμένουν απάντηση από άλλο νήμα ή να τους μπλοκάρει άλλο νήμα.

Μπορείτε να προσαρμόσετε τους πόρους που εκχωρείτε σε νήματα που δημιουργείτε χρησιμοποιώντας το pthread. Αυτή μπορεί να είναι μια προσαρμοσμένη πολιτική προγραμματισμού ή μπορείτε να επιλέξετε αλγόριθμους προγραμματισμού, όπως FIFO ή Round-robin, αν θέλετε.