Technologieaustausch

Reaktorserver mit hoher Parallelität [mittel]

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

4. Prozesssteuerung und Prozesssynchronisation

1. Signal

1.1 Grundbegriffe von Signalen

Signal (Signal) ist ein Software-Interrupt. Es handelt sich um eine Methode zum Übertragen von Nachrichten zwischen Prozessen. Es wird verwendet, um den Prozess darüber zu informieren, dass ein Ereignis aufgetreten ist, es kann jedoch keine Daten an den Prozess weitergeben.

Es gibt viele Gründe, warum Signale in der Shell generiert werdenkillUndkillallBefehl zum Senden eines Signals:

kill -信号的类型 进程编号
killall -信号的类型 进程名
  • 1
  • 2

1.2 Arten von Signalen

SignalnameSignalwertStandardverarbeitungsaktionGrund für die Signalisierung
SEUFZEND1ADas Terminal hängt oder der Steuerungsprozess wird beendet
ZEICHEN2ATastaturunterbrechung Strg+c
SIGQUIT3CDie Escape-Taste der Tastatur wird gedrückt
SIEGEL4CIllegale Anweisung
SIGTRAP5CHaltepunktanweisungen
SIGABRT6CAbbruchsignal ausgegeben von abort(3)
SIGBUS7CBusfehler
SIGFPE8CGleitkomma-Ausnahme
SIGKILL9Akill -9 beendet den Prozess, dieses Signal kann nicht abgefangen und ignoriert werden
SIGUSR110ABenutzerdefiniertes Signal 1
SIGSEGV11CUngültige Speicherreferenz (Array außerhalb der Grenzen, Nullzeigeroperation)
SIGUSR212ABenutzerdefiniertes Signal 2
SIGPIPE13ADaten ohne Lesevorgang in eine Pipe schreiben
SIGALRM14AWeckersignal, Signal, das von der Funktion alarm() gesendet wird
SIGTERM15ABeendigungssignal, das standardmäßig gesendete Signal
SIGSTKFLT16AStapelfehler
SIGCHLD17BWird ausgegeben, wenn der untergeordnete Prozess endet
SIGCONT18DSetzen Sie einen gestoppten Prozess fort
SIGSTOP19DProzess stoppen
SIGTSTP20DTerminal drücken Sie die Stopp-Taste
SIGTTIN21DHintergrundprozessanforderungen zum Lesen des Terminals
SIGTTOU22DDer Hintergrundprozess fordert zum Schreiben auf das Terminal auf
SIGURG23BNotfallzustandserkennung (Steckdose)
SIGXCPU24CCPU-Zeitlimit überschritten
SIGXFSZ25CDateigrößenbeschränkung überschritten
SIGVTALRM26Avirtuelles Taktsignal
SIGPROF27AAnalysieren Sie Taktsignale
ZEICHENWINCH28BFenstergröße ändert sich
SIGPOLL29BAbfrage (Sys V)
SIGPWR30AStromausfall
SIGSYS31CUnzulässiger Systemaufruf

Die Standardaktion von A besteht darin, den Prozess zu beenden.

Die Standardaktion von B besteht darin, dieses Signal zu ignorieren.

Die Standardaktion von C besteht darin, den Prozess zu beenden und einen Kernel-Image-Dump zu erstellen.

Die Standardaktion von D besteht darin, den Prozess zu stoppen, und das Programm, das in den gestoppten Zustand wechselt, kann weiter ausgeführt werden.

1.3 Signalverarbeitung

Es gibt drei Möglichkeiten für Prozesse, Signale zu verarbeiten:

  1. Zur Verarbeitung dieses Signals wird die Standardoperation des Systems verwendet. Die Standardoperation der meisten Signale besteht darin, den Prozess zu beenden.
  2. Stellen Sie die Interrupt-Verarbeitungsfunktion ein. Nach dem Empfang des Signals wird die Funktion es verarbeiten.
  3. Ignorieren Sie ein Signal und machen Sie nichts mit dem Signal, als ob es nie passiert wäre.

signal()Funktionen können festlegen, wie das Programm mit Signalen umgeht.

Funktionsdeklaration:

#include <signal.h>

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
  • 1
  • 2
  • 3
  • 4

Parameterbeschreibung:

  • sig:Geben Sie das zu erfassende Signal an.
  • func : Zeiger auf Signalverarbeitungsfunktion. Die Verarbeitungsfunktion muss einen ganzzahligen Parameter empfangen, der die erfasste Signalnummer ist.
  1. SIG_DFL Das Makro :SIG_DFL stellt die Standard-Signalverarbeitungsmethode dar.verwendenSIG_DFLalssignalDer zweite Parameter der Funktion gibt an, dass die Standardverarbeitungsmethode des Systems für das Signal verwendet wird.
  2. SIG_IGN Das Makro :SIG_IGN bedeutet, das Signal zu ignorieren.verwendenSIG_IGNalssignal Der zweite Parameter der Funktion gibt an, dass der Prozess, wenn er das Signal empfängt, es ignoriert und keine Verarbeitung durchführt. Dadurch kann verhindert werden, dass Prozesse unter bestimmten Umständen unerwartet beendet oder unterbrochen werden.
  3. SIG_ERR:SIG_ERR Makros werden verwendet, um Fehler anzuzeigen.es ist nicht sosignalDer zweite Parameter der Funktion wird stattdessen als verwendetsignal Der Rückgabewert der Funktion zeigt an, dass der Aufruf fehlgeschlagen ist.WennsignalWenn der Aufruf der Funktion fehlschlägt, wird sie zurückgegebenSIG_ERR .Dies wird typischerweise zur Erkennung und Verarbeitung verwendetsignalFehler beim Funktionsaufruf.

Bild-20240709113614147

Bild-20240709113230874

Bild-20240709113240944

1.4 Wozu dienen Signale?

Wenn Sie das Dienstprogramm im Hintergrund ausführen möchten, ist es keine gute Idee, es zu beenden, denn wenn der Prozess beendet wird, wird er plötzlich beendet und es werden keine Nacharbeiten veranlasst.

Wenn Sie ein Signal an das Dienstprogramm senden, ruft das Dienstprogramm nach dem Empfang des Signals eine Funktion auf und schreibt den Folgecode in die Funktion, und das Programm kann auf geplante Weise beendet werden.

Durch Senden eines Signals von 0 an das Dienstprogramm kann festgestellt werden, ob das Programm aktiv ist.

Bild-20240709135336848

1.5 Signale senden

Das Linux-Betriebssystem bietet kill Undkillall Der Befehl sendet ein Signal an das Programm, das Sie verwenden könnenkill() Bibliotheksfunktionen senden Signale an andere Prozesse.

Funktionsdeklaration:

int kill(pid_t pid, int sig);
  • 1

kill() Die Funktion übernimmt die Parametersig Das angegebene Signal wird an den Parameter übergebenpid angegebenen Prozess.

Parameter pid Es gibt mehrere Situationen:

  1. pid > 0 Übergeben Sie das Signal an den Prozess alspid Verfahren.
  2. pid = 0 Leiten Sie das Signal an alle Prozesse in derselben Prozessgruppe wie der aktuelle Prozess weiter. Es wird häufig vom übergeordneten Prozess verwendet, um Signale an den untergeordneten Prozess zu senden.
  3. pid < -1 Übergeben Sie das Signal an die Prozessgruppen-ID von|pid| aller Prozesse.
  4. pid = -1 Leitet das Signal an alle Prozesse weiter, die die Berechtigung zum Senden des Signals haben, jedoch nicht an den Prozess, der das Signal gesendet hat.

2. Prozessbeendigung

Es gibt 8 Möglichkeiten, einen Prozess zu beenden, davon sind 5 normale Beendigungen:

  1. existieren main() Für Funktionenreturn zurückkehren;
  2. Wird in einer beliebigen Funktion aufgerufen exit() Funktion;
  3. Wird in einer beliebigen Funktion aufgerufen _exit() oder_Exit() Funktion;
  4. Der letzte Thread startet von seiner Startup-Routine (Thread-Hauptfunktion) mit return zurückkehren;
  5. Im letzten Thread aufgerufen pthread_exit() zurückkehren;

Es gibt drei Möglichkeiten, den Vorgang abnormal zu beenden:

  1. überweisen abort() Funktionsabbruch;
  2. Ein Signal wird empfangen;
  3. Der letzte Thread antwortet auf die Abbruchanfrage.

2.1 Status der Prozessbeendigung

existieren main() In der Funktion,return Der zurückgegebene Wert ist der Beendigungsstatus, falls nichtreturn Erklärung oder Anrufexit(), dann ist der Beendigungsstatus des Prozesses 0.

Sehen Sie sich in der Shell den Status der Prozessbeendigung an:

echo $?
  • 1

3 Funktionen zum normalen Beenden des Prozesses (exit() Und_Exit() wird durch ISO C spezifiziert,_exit() wird durch POSIX angegeben):

void exit(int status);
void _exit(int status);
void _Exit(int status);
  • 1
  • 2
  • 3

status Der Status der Prozessbeendigung.

Bild-20240709143530327

Bild-20240709143615950

2.2 Problem mit der Ressourcenfreigabe

  • return Gibt an, dass bei der Rückkehr der Funktion der Destruktor des lokalen Objekts aufgerufen wird.main() in Funktionreturn Der Destruktor des globalen Objekts wird ebenfalls aufgerufen.
  • exit() Gibt an, dass der Prozess beendet werden soll. Der Destruktor des lokalen Objekts wird nicht aufgerufen, sondern nur der Destruktor des globalen Objekts.
  • _exit() Und_Exit() Beenden Sie den Vorgang direkt und es werden keine Aufräumarbeiten durchgeführt.

2.3 Beendigungsfunktion des Prozesses

Der Prozess ist verfügbar atexit() Durch die Funktionsregistrierung werden Funktionen (bis zu 32) beendet. Diese Funktionen werden ausgeführtexit() Automatisch aufgerufen.

int atexit(void (*function)(void));
  • 1

exit() Die Reihenfolge, in der die Terminierungsfunktionen aufgerufen werden, ist ab dem Zeitpunkt der Registrierung umgekehrt.

Bild-20240709143824286

Bild-20240709143830549

3. Rufen Sie das ausführbare Programm auf

3.1 system()-Funktion

system()Die Funktion stellt eine einfache Methode zum Ausführen des Programms bereit und übergibt das Programm und die Parameter, die ausgeführt werden müssen, als Zeichenfolge.system()Funktioniert einfach.

Funktionsdeklaration:

int system(const char * string);
  • 1

system()Der Rückgabewert der Funktion ist problematischer.

  1. Wenn das ausgeführte Programm nicht existiert,system()Die Funktion gibt einen Wert ungleich Null zurück;
  2. Wenn die Ausführung des Programms erfolgreich ist und der Ausführungsstatus des ausgeführten Programms 0 ist,system()Die Funktion gibt 0 zurück;
  3. Wenn die Ausführung des Programms erfolgreich ist und der Beendigungsstatus des ausgeführten Programms nicht 0 ist,system()Die Funktion gibt einen Wert ungleich Null zurück.

3.2 Exec-Funktionsfamilie

execFunktionsfamilien bieten eine weitere Möglichkeit, Programme (Binärdateien oder Shell-Skripte) innerhalb eines Prozesses aufzurufen.

execDie Funktionsfamilie wird wie folgt deklariert:

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Beachten

  1. Wenn die Ausführung des Programms fehlschlägt, wird -1 direkt zurückgegeben und der Grund für den Fehler gespeicherterrnoMitte.
  2. Die Prozessnummer des neuen Prozesses ist dieselbe wie die des ursprünglichen Prozesses, aber der neue Prozess ersetzt das Codesegment, das Datensegment und den Stapel des ursprünglichen Prozesses.
  3. Wenn die Ausführung erfolgreich ist, kehrt die Funktion nicht zurück, wenn sie im Hauptprogramm erfolgreich aufgerufen wirdexecDanach ersetzt das aufgerufene Programm das aufrufende Programm, d.execKein Code, nachdem die Funktion ausgeführt wird.
  4. In der tatsächlichen Entwicklung wird am häufigsten verwendetexecl()Undexecv(), andere werden selten verwendet.

4. Erstellen Sie einen Prozess

4.1 Linux-Prozesse 0, 1 und 2

Alle Prozesse im gesamten Linux-System liegen in einer Baumstruktur vor.

  • **Prozess Nr. 0 (Systemprozess)** ist der Vorfahre aller Prozesse. Er hat die Prozesse Nr. 1 und Nr. 2 erstellt.
  • **Prozess Nr. 1 (systemd)** ist für die Kernel-Initialisierung und Systemkonfiguration verantwortlich.
  • **Prozess Nr. 2 (kthreadd)** ist für die Planung und Verwaltung aller Kernel-Threads verantwortlich.

verwendenpstreeSie können den Prozessbaum mit dem folgenden Befehl anzeigen:

pstree -p 进程编号
  • 1

4.2 Prozessidentifikation

Jeder Prozess verfügt über eine eindeutige Prozess-ID, die durch eine nicht negative Ganzzahl dargestellt wird. Obwohl eindeutig, können Prozess-IDs wiederverwendet werden. Wenn ein Prozess beendet wird, wird seine Prozess-ID zu einem Kandidaten für die Wiederverwendung. Linux verwendet einen verzögerten Wiederverwendungsalgorithmus, sodass sich die ID eines neu erstellten Prozesses von der ID des kürzlich beendeten Prozesses unterscheidet. Dadurch wird verhindert, dass neue Prozesse mit einem beendeten Prozess mit derselben ID verwechselt werden.

Funktion zum Abrufen der Prozess-ID:

pid_t getpid(void);    // 获取当前进程的ID。
pid_t getppid(void);   // 获取父进程的ID。
  • 1
  • 2

4.3 fork()-Funktion

Ein vorhandener Prozess kann aufgerufen werdenfork()Funktion erstellt einen neuen Prozess.

Funktionsdeklaration:

pid_t fork(void);
  • 1

Darauf ankommenfork()Der neu erstellte Prozess wird als untergeordneter Prozess bezeichnet.

fork() Die Funktion wird einmal aufgerufen, kehrt aber zweimal zurück. Der Unterschied zwischen den beiden Rückgaben besteht darin, dass der Rückgabewert des untergeordneten Prozesses 0 ist, während der Rückgabewert des übergeordneten Prozesses die Prozess-ID des neu erstellten untergeordneten Prozesses ist.

Der untergeordnete Prozess und der übergeordnete Prozess werden weiterhin ausgeführtfork()Der Code danach, Der untergeordnete Prozess ist eine Kopie des übergeordneten Prozesses. Der untergeordnete Prozess verfügt über eine Kopie des Datenraums, des Heaps und des Stapels des übergeordneten Prozesses (Hinweis: Der untergeordnete Prozess besitzt eine Kopie, die nicht mit dem übergeordneten Prozess geteilt wird).

fork()Danach ist die Ausführungsreihenfolge der übergeordneten und untergeordneten Prozesse undefiniert.

Bild-20240709221535371

Bild-20240709221546617

4.4 Zwei Verwendungsmöglichkeiten von fork()

  1. Der übergeordnete Prozess möchte sich selbst kopieren, und dann führen der übergeordnete Prozess und der untergeordnete Prozess jeweils unterschiedlichen Code aus.Diese Verwendung kommt in Netzwerkdienstprogrammen sehr häufig vor. Der übergeordnete Prozess wartet auf die Verbindungsanforderung des Clientsfork()Lassen Sie den untergeordneten Prozess diese Anforderungen verarbeiten, während der übergeordnete Prozess weiterhin auf die nächste Verbindungsanforderung wartet.
  2. Der Prozess möchte ein anderes Programm ausführen.Diese Verwendung kommt in Shells sehr häufig vor, von denen der untergeordnete Prozess ausgehtfork()Gleich nach der Rückkehr angerufenexec

4.5 Freigegebene Dateien

fork()Eine Funktion besteht darin, dass im übergeordneten Prozess geöffnete Dateideskriptoren in den untergeordneten Prozess kopiert werden und der übergeordnete Prozess und der untergeordnete Prozess denselben Dateioffset verwenden.

Wenn ein übergeordneter Prozess und ein untergeordneter Prozess ohne jegliche Synchronisation in eine Datei schreiben, auf die derselbe Deskriptor verweist, kann es zu einer Vermischung ihrer Ausgaben kommen.

Bild-20240709222929369

Bild-20240709222803641

An diesem Punkt können Sie sehen, dass es nur 100.000 Datenzeilen gibt.

Bild-20240709222853769

Bild-20240709223236254

Zu diesem Zeitpunkt sollten 200.000 Datenzeilen vorhanden sein, da der Dateischreibvorgang nicht atomar ist. Wenn kein Synchronisierungsmechanismus vorhanden ist, können zwei Prozesse gleichzeitig versuchen, verschiedene Teile der Datei zu schreiben Die Daten stören sich gegenseitig.

4.6 vfork()-Funktion

vfork()Funktionsaufrufe und Rückgabewerte sind die gleichen wiefork()Gleich, aber ihre Semantik ist unterschiedlich.

vfork()Die Funktion wird verwendet, um einen neuen Prozess zu erstellen, dessen Zweck es istexecEin neues Programm, das den Adressraum des übergeordneten Prozesses nicht kopiert, da der untergeordnete Prozess sofort aufgerufen wirdexec , sodass der Adressraum des übergeordneten Prozesses nicht verwendet wird. Wenn der untergeordnete Prozess den Adressraum des übergeordneten Prozesses verwendet, können unbekannte Ergebnisse auftreten.

vfork()Undfork()Ein weiterer Unterschied ist:vfork()Stellen Sie sicher, dass der untergeordnete Prozess zuerst ausgeführt wird, und rufen Sie ihn im untergeordneten Prozess aufexecoderexitAnschließend nimmt der übergeordnete Prozess den Betrieb wieder auf.

5. Zombie-Prozess

Im Betriebssystem bezieht sich ein Zombie-Prozess auf einen untergeordneten Prozess, der beendet wurde, dessen übergeordneter Prozess jedoch seinen Beendigungsstatus noch nicht gelesen hat. Obwohl der Zombie-Prozess nicht mehr ausgeführt wird, belegt er immer noch einen Eintrag in der Prozesstabelle, sodass der Kernel die Exit-Statusinformationen des Prozesses (z. B. Prozess-ID, Exit-Status usw.) speichern kann, bis der übergeordnete Prozess diese Informationen liest.

5.1 Ursachen von Zombie-Prozessen

Wenn der übergeordnete Prozess vor dem untergeordneten Prozess beendet wird, wird der untergeordnete Prozess von Prozess 1 gehostet (dies ist auch eine Möglichkeit, den Prozess im Hintergrund laufen zu lassen).

Wenn der untergeordnete Prozess vor dem übergeordneten Prozess beendet wird und der übergeordnete Prozess die Exit-Informationen des untergeordneten Prozesses nicht verarbeitet, wird der untergeordnete Prozess zu einem Zombie-Prozess.

5.2 Der Schaden von Zombie-Prozessen

Der Kernel behält eine Datenstruktur für jeden untergeordneten Prozess bei, einschließlich Prozessnummer, Beendigungsstatus, verbrauchter CPU-Zeit usw. Wenn der übergeordnete Prozess die Exit-Informationen des untergeordneten Prozesses verarbeitet, gibt der Kernel diese Datenstruktur frei. Wenn der übergeordnete Prozess die Exit-Informationen des untergeordneten Prozesses nicht verarbeitet, gibt der Kernel diese Datenstruktur nicht frei und die Prozessnummer des untergeordneten Prozesses ist immer belegt. Die im System verfügbaren Prozessnummern sind begrenzt. Wenn eine große Anzahl von Zombie-Prozessen generiert wird, kann das System keine neuen Prozesse generieren, da keine Prozessnummern verfügbar sind.

5.3 Methoden zur Vermeidung von Zombie-Prozessen

  1. Umgang mit dem SIGCHLD-Signal : Wenn der untergeordnete Prozess beendet wird, sendet der Kernel das SIGCHLD-Signal an den übergeordneten Prozess.Wenn der übergeordnete Prozess verwendetsignal(SIGCHLD, SIG_IGN)Benachrichtigen Sie den Kernel darüber, dass er nicht am Beenden des untergeordneten Prozesses interessiert ist, und seine Datenstruktur wird sofort nach dem Beenden des untergeordneten Prozesses freigegeben.
  2. verwendenwait()/waitpid()Funktion: Der übergeordnete Prozess wartet auf das Ende des untergeordneten Prozesses, indem er diese Funktionen aufruft, und erhält seinen Exit-Status, wodurch die vom untergeordneten Prozess belegten Ressourcen freigegeben werden.
pid_t wait(int *stat_loc); 
pid_t waitpid(pid_t pid, int *stat_loc, int options); 
pid_t wait3(int *status, int options, struct rusage *rusage); 
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
  • 1
  • 2
  • 3
  • 4

Der Rückgabewert ist die Nummer des Kindprozesses.

stat_loc Ist die Information über die Beendigung des untergeordneten Prozesses:

a) Bei normaler Beendigung wird das Makro WIFEXITED(stat_loc) Gibt true zurück, MakroWEXITSTATUS(stat_loc) Der Kündigungsstatus kann abgerufen werden;

b) Wenn es abnormal beendet wird, wird das Makro WTERMSIG(stat_loc) Ruft das Signal zum Beenden des Prozesses ab.

Bild-20240709230911352

Bild-20240709231034423

Bild-20240709231050581

Bild-20240709231124375

Bild-20240709231140813

Wenn der übergeordnete Prozess ausgelastet ist, können Sie ihn erfassen SIGCHLD Signal, wird in der Signalverarbeitungsfunktion aufgerufenwait()/waitpid()

Bild-20240709231439475

Bild-20240709231422927

6.Mehrere Prozesse und Signale

[Signale zwischen Prozessen senden](##1.5 Signale senden)

Wenn in einem Multiprozess-Dienstprogramm der Unterprozess ein Exit-Signal empfängt, wird der Unterprozess von selbst beendet.

Wenn der übergeordnete Prozess ein Exit-Signal empfängt, sollte er Exit-Signale an alle untergeordneten Prozesse senden und sich dann selbst beenden.

Bild-20240711222919564

Bild-20240711222900141

Bild-20240711223111481

7. Gemeinsamer Speicher

Multithreads teilen sich den Adressraum eines Prozesses,Wenn mehrere Threads auf denselben Speicher zugreifen müssen, verwenden Sie einfach globale Variablen.

Bei mehreren Prozessen ist der Adressraum jedes Prozesses unabhängig und wird nicht gemeinsam genutzt.Wenn mehrere Prozesse auf denselben Speicher zugreifen müssen, können keine globalen Variablen verwendet werden, sondern nur gemeinsam genutzter Speicher.

Shared Memory ermöglicht den Zugriff mehrerer Prozesse (keine Blutbeziehung zwischen Prozessen erforderlich) auf denselben Speicherplatz. Dies ist die effektivste Möglichkeit, Daten zwischen mehreren Prozessen zu teilen und zu übertragen. Prozesse können Shared Memory mit ihrem eigenen Adressraum verbinden. Wenn ein Prozess die Daten im Shared Memory ändert, ändern sich auch die von anderen Prozessen gelesenen Daten.

Der gemeinsam genutzte Speicher bietet keinen Sperrmechanismus. Das heißt, wenn ein Prozess den gemeinsam genutzten Speicher liest/schreibt, verhindert er nicht, dass andere Prozesse ihn lesen/schreiben.Wenn Sie das Lesen/Schreiben des gemeinsam genutzten Speichers sperren möchten, können Sie ein Semaphor verwenden . Linux bietet eine Reihe von Funktionen zum Betreiben von Shared Memory.

7.1 Shmget-Funktion

Mit dieser Funktion wird Shared Memory erstellt/erworben.

 int shmget(key_t key, size_t size, int shmflg);
  • 1
  • Schlüssel Der Schlüsselwert des gemeinsam genutzten Speichers ist eine Ganzzahl (typedef unsigned int key_t), im Allgemeinen beispielsweise hexadezimal 0x5005, die Schlüssel verschiedener gemeinsamer Erinnerungen können nicht gleich sein.
  • Größe Größe des gemeinsam genutzten Speichers in Bytes.
  • Abonnieren Zugriffsberechtigungen für Shared Memory sind beispielsweise mit Dateiberechtigungen identisch0666|IPC_CREAT Gibt an, dass der gemeinsam genutzte Speicher erstellt werden soll, wenn er nicht vorhanden ist.
  • Rückgabewert: Gibt bei Erfolg die ID des gemeinsam genutzten Speichers (eine Ganzzahl größer als 0) zurück, bei Fehler -1 (das System verfügt nicht über genügend Speicher und keine Berechtigungen).

Bild-20240711224223200

Bild-20240711224212293

verwenden ipcs -m Sie können den gemeinsam genutzten Speicher des Systems anzeigen, einschließlich: Schlüssel (key), ID des gemeinsam genutzten Speichers (shmid), Besitzer (owner), Berechtigungen (perms) und Größe (bytes).

verwenden ipcrm -m 共享内存id Shared Memory kann wie folgt manuell gelöscht werden:

Bild-20240711225202860

Hinweis: Container können nicht für Datentypen im gemeinsam genutzten Speicher verwendet werden, es können nur Basisdatentypen verwendet werden.

7.2 Shmat-Funktion

Diese Funktion wird verwendet, um gemeinsam genutzten Speicher mit dem Adressraum des aktuellen Prozesses zu verbinden.

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • 1
  • schmid Darauf ankommenshmget() Der von der Funktion zurückgegebene Shared-Memory-Bezeichner.
  • Abonnieren Geben Sie den Adressort an, an dem der gemeinsam genutzte Speicher mit dem aktuellen Prozess verbunden ist. Geben Sie normalerweise 0 ein, damit das System die Adresse des gemeinsam genutzten Speichers auswählen kann.
  • Abonnieren Flag-Bit, normalerweise mit 0 gefüllt.

Gibt die Startadresse des gemeinsam genutzten Speichers zurück, wenn der Aufruf erfolgreich ist, und kehrt zurück, wenn er fehlschlägt. (void *)-1

7.3 shmdt-Funktion

Diese Funktion wird verwendet, um gemeinsam genutzten Speicher vom aktuellen Prozess zu trennen, was äquivalent ist zu shmat() Die Umkehroperation einer Funktion.

int shmdt(const void *shmaddr);
  • 1
  • Abonnieren shmat() Die von der Funktion zurückgegebene Adresse.

Gibt 0 zurück, wenn der Aufruf erfolgreich ist, und -1, wenn er fehlschlägt.

7.4 shmctl-Funktion

Diese Funktion wird zum Betreiben des gemeinsam genutzten Speichers verwendet. Der am häufigsten verwendete Vorgang ist das Löschen des gemeinsam genutzten Speichers.

int shmctl(int shmid, int command, struct shmid_ds *buf);
  • 1
  • schmid shmget() Die von der Funktion zurückgegebene Shared-Memory-ID.
  • Befehl Anweisungen zum Betrieb des Shared Memory. Wenn Sie Shared Memory löschen möchten, füllen Sie es ausIPC_RMID
  • buf Die Adresse der Datenstruktur, die den gemeinsam genutzten Speicher betreibt. Wenn Sie den gemeinsam genutzten Speicher löschen möchten, geben Sie 0 ein.

Gibt 0 zurück, wenn der Aufruf erfolgreich ist, und -1, wenn er fehlschlägt.

Hinweis, Verwendung root Der erstellte gemeinsame Speicher kann von normalen Benutzern unabhängig von den erstellten Berechtigungen nicht gelöscht werden.

Bild-20240711230653886

Bild-20240711230522921

7.5 Runde Warteschlange

7.6 Zirkuläre Warteschlange basierend auf gemeinsam genutztem Speicher

Gibt 0 zurück, wenn der Aufruf erfolgreich ist, und -1, wenn er fehlschlägt.

7.4 shmctl-Funktion

Diese Funktion wird zum Betreiben des gemeinsam genutzten Speichers verwendet. Der am häufigsten verwendete Vorgang ist das Löschen des gemeinsam genutzten Speichers.

int shmctl(int shmid, int command, struct shmid_ds *buf);
  • 1
  • schmid shmget() Die von der Funktion zurückgegebene Shared-Memory-ID.
  • Befehl Anweisungen zum Betrieb des Shared Memory. Wenn Sie Shared Memory löschen möchten, füllen Sie es ausIPC_RMID
  • buf Die Adresse der Datenstruktur, die den gemeinsam genutzten Speicher betreibt. Wenn Sie den gemeinsam genutzten Speicher löschen möchten, geben Sie 0 ein.

Gibt 0 zurück, wenn der Aufruf erfolgreich ist, und -1, wenn er fehlschlägt.

Hinweis, Verwendung root Der erstellte gemeinsame Speicher kann von normalen Benutzern unabhängig von den erstellten Berechtigungen nicht gelöscht werden.

[Externer Link Bilder werden übertragen...(img-v6qW3XRA-1720711279572)]

[Externer Link Bilder werden übertragen...(img-CG0tGAne-1720711279572)]Die Übertragung des externen Linkbildes ist möglicherweise über einen Anti-Leeching-Mechanismus verfügt. Es wird empfohlen, das Bild zu speichern und direkt hochzuladen.
Die Übertragung des externen Linkbildes ist möglicherweise über einen Anti-Leeching-Mechanismus verfügt. Es wird empfohlen, das Bild zu speichern und direkt hochzuladen.
Die Übertragung des externen Linkbildes ist möglicherweise über einen Anti-Leeching-Mechanismus verfügt. Es wird empfohlen, das Bild zu speichern und direkt hochzuladen.

7.5 Runde Warteschlange

7.6 Zirkuläre Warteschlange basierend auf gemeinsam genutztem Speicher