Systemaufrufe und Kontextaustausch
Wie funktioniert eine Benutzerprogrammanforderung vom Kernel?
Die in diesem Blog verfassten Artikel wurden mit dem Ziel erstellt, zu unterrichten. Außerdem können die Informationen im Artikel falsch sein, also seien Sie bitte vorsichtig.
Benutzermodusprogramme können Festplatten- oder Netzwerkgeräte nicht direkt steuern. Stattdessen fordert es Arbeit vom Betriebssystem an, und diese formale Anforderungsmethode wird als Systemaufruf bezeichnet.
Wie unterscheidet es sich von einem regulären Funktionsaufruf?
Ein allgemeiner Funktionsaufruf ändert nur den Ausführungsort innerhalb desselben Privilegienbereichs. Bei Systemaufrufen ändern sich die CPU-Berechtigungen vom Benutzermodus in den Kernelmodus, und nachdem der Kernel die Anforderung verarbeitet hat, kehrt er in den Benutzermodus zurück.
Generischer Funktionsaufruf
Benutzercode → Benutzerfunktion → Benutzercode
Systemaufruf
Benutzercode → Kernel-Eintrag → Berechtigungs- und Argumentprüfung → Kernel-Operation → Benutzercode
Funktionen wie das Öffnen von Dateien, die Speicherzuordnung, die Socket-Kommunikation und die Prozesserstellung verwenden letztendlich Systemaufrufe. Programmierer rufen normalerweise die Betriebssystem-API oder die Standardbibliothek auf, und der entsprechende Systemaufruf wird in der darunter liegenden Ebene ausgeführt.
Es unterscheidet sich vom Kontextwechsel
Das Aufrufen eines Systemaufrufs führt nicht unbedingt zu einer Änderung eines anderen Prozesses. Derselbe Thread kann in den Kernel-Modus wechseln, die Anforderung verarbeiten und sofort zurückkehren.
Beim Kontextwechsel wird das Ausführungsziel geändert, indem der aktuelle Ausführungsstatus gespeichert und der Status eines anderen Threads oder Prozesses wiederhergestellt wird.
Systemaufruf: Derselbe Executor fordert Arbeit vom Kernel an.
Kontextwechsel: Die CPU ändert das Subjekt selbst, um es auszuführen
Allerdings können Systemaufrufe, die auf Dateien oder Netzwerkdaten warten müssen, den aktuellen Thread in einen Wartezustand versetzen. In der Zwischenzeit führt das Betriebssystem andere Threads aus, um eine Verschwendung der CPU zu vermeiden, und zu diesem Zeitpunkt kann es zu einem Kontextwechsel kommen.
Systemaufrufe sind nicht kostenlos
Privilegienwechsel und Parameterprüfung kosten Geld. Dies ist einer der Gründe, warum es vorteilhaft ist, kleine Daten in einem Puffer zu sammeln und auf einmal zu schreiben, anstatt tausende Male ein Byte zu schreiben.
std::string buffer;
for (const auto& line : lines)
{
buffer += line;
buffer += '\n';
}
file.write(buffer.data(), buffer.size());
Dies bedeutet jedoch nicht, dass Systemaufrufe unbedingt vermieden werden sollten. Es handelt sich um eine notwendige Grenze für das Betriebssystem, um Ressourcen sicher zu verwalten, und es empfiehlt sich, die Anzahl der Aufrufe und Wartemethoden zu prüfen, wenn Leistungsprobleme festgestellt werden.