Heim > Artikel > Betrieb und Instandhaltung > So implementieren Sie die prozessübergreifende Linux-Kommunikation
Gemeinsamer Speicher kann als die nützlichste Methode zur Kommunikation zwischen Prozessen und die schnellste Form von IPC bezeichnet werden, was bedeutet, dass derselbe physische Speicher vorhanden ist Durch die Zuordnung zu den jeweiligen Prozessadressräumen der Prozesse A und B kann Prozess A gleichzeitig Aktualisierungen von Daten im gemeinsam genutzten Speicher durch Prozess B sehen und umgekehrt.
Da sich mehrere Prozesse denselben Speicherbereich teilen, sind eine Art Synchronisationsmechanismus, Mutex-Sperren und Semaphoren erforderlich.
Vorteile: Hohe Effizienz, der Prozess kann Speicher direkt lesen und schreiben, ohne Daten zu kopieren, während Kommunikationsmethoden wie Pipes und Nachrichtenwarteschlangen vier Datenkopien im Kernel und im Benutzerbereich erfordern.
Und nur beim Aufheben der Zuordnung wird der Inhalt des gemeinsam genutzten Speichers zum Gedenken geschrieben.
Der gemeinsam genutzte Speicher verwendet Kernelobjekte, um verschiedenen Prozessen zu ermöglichen, einen Platz in ihrem eigenen virtuellen Adressraum zuzuweisen und ihn demselben physischen Speicherraum zuzuordnen. Auf diesen physischen Speicherplatz kann jeder ihm zugeordnete Prozess zugreifen. (Kritische Ressource)
Gemeinsamer Speicher ermöglicht es „zwei unabhängigen Prozessen, auf denselben logischen Speicher zuzugreifen“. Shared Memory ist eine sehr effiziente Möglichkeit, Daten zwischen zwei laufenden Prozessen zu teilen und zu übertragen.
Der von verschiedenen Prozessen gemeinsam genutzte Speicher wird normalerweise als dasselbe Segment des physischen Speichers angeordnet.
Prozesse können dasselbe Segment des gemeinsam genutzten Speichers mit ihrem eigenen Adressraum verbinden, und alle Prozesse können auf Adressen im gemeinsam genutzten Speicher zugreifen, als ob ihnen mit der C-Sprachfunktion malloc() Speicher zugewiesen wäre.
Und wenn ein Prozess Daten in den gemeinsam genutzten Speicher schreibt, wirken sich die Änderungen sofort auf alle anderen Prozesse aus, die auf denselben gemeinsam genutzten Speicher zugreifen können.
mmap() und die damit verbundenen Systemaufrufe
mmap ist nicht vollständig für IPC konzipiert, es ist lediglich eine Anwendungsmethode von IPC. Es bietet selbst eine Möglichkeit, auf normale Dateien zuzugreifen, wie auf den normalen Speicher.
Erreicht durch die Verwendung virtueller Speichersegmente mit speziellen Berechtigungssätzen. Beim Lesen oder Schreiben eines solchen virtuellen Speichersegments liest und schreibt das Betriebssystem den entsprechenden Teil der Festplattendatei. Diemmap-Funktion erstellt einen Zeiger auf einen Speicherbereich, der mit dem Inhalt einer Datei verknüpft ist, auf die über einen offenen Dateideskriptor zugegriffen werden kann
wird wie folgt erklärt: mmap()#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);kann per Offset-Parameter übergeben werden, um die zu ändern Startoffsetwert der Daten in der Datei, auf die über das gemeinsam genutzte Speichersegment zugegriffen wird. Der Deskriptor für offene Dateien wird durch den fd-Parameter angegeben. Die Menge der Daten, auf die zugegriffen werden kann (d. h. die Länge des Speichersegments), wird durch den Längenparameter festgelegt. Sie können die Verwendung einer bestimmten Speicheradresse über den Parameter addr anfordern. Wenn sein Wert Null ist, wird der Ergebniszeiger automatisch zugewiesen. Wenn Sie diese Vorgehensweise nicht befolgen, verringert sich die Portabilität Ihres Programms, da die verfügbaren Adressbereiche auf verschiedenen Systemen unterschiedlich sind. Der Parameter prot wird verwendet, um die Zugriffsberechtigungen des Speichersegments festzulegen. Es ist das Ergebnis der bitweisen ODER-Verknüpfung der folgenden konstanten Werte: PROT_READ Das Speichersegment ist lesbar. PROT_WRITE Das Speichersegment ist beschreibbar.
Verwenden Sie die Speicherzuordnung Wird von gewöhnlichen Dateien bereitgestellt und kann zwischen allen Prozessen verwendet werden. Bei Verwendung dieser Methode muss zunächst eine Datei geöffnet oder erstellt und dann ngmmap aufgerufen werden. Der typische Aufrufcode lautet wie folgt:
fd = open(name.falg.mode); if(fd < 0) ptr = mmap(NULL,len.PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
使用特殊文件提供的内存映射,适用于具有亲缘关系的进程之间,由于父子进程特殊的亲缘关系,在父进程中先调用mmap,调用fork,那么在代用fork之后,子进程可以继承父进程匿名映射后的地址空间,同样也继承mmap返回的地址,这样父子进程就可以通过映射区域进行通信了。(注意:一般来说,子进程单独维护从父进程继承而来的一些变量,而mmap()返回的地址由父子进程共同维护)【具体使用实现敬请期待博主整理】
用于解除内存映射,取消参数start所指的映射内存的起始地址,参数length则是欲取消的内存大小,当进程结束或者利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述符时不会解除映射。
#include <sys/mman.h> int munmap(void *addr, size_t length);
与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h
中。
1.获取或创建内核对象,并且制定共享内存的大小(系统分配物理空间是,按照页进行分配)
int shmget(key_t key, int size, int flag);
只是创建内核对象,并申请物理空间
key_t key
:与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,不同的进程通过相同的key值来访问同一块共享内存
int size
:size以字节为单位指定需要共享的内存容量
int flag
:falg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。
返回值
调用成功后,shmget()函数会返回一个非负整数,用作后续共享内存函数的共享内存标识符,该标识符与key相关。
调用失败返回-1.
2.分配自己虚拟地址空间映射到共享内存的物理空间上
void *shmat(int shmid,const void *addr, int flag);
shmid
:shmid是由shmget()函数返回的共享内存标识。
void *addr
:addr指定共享内存连接到当前进程中的地址位置,通常为NULL,表示让系统来选择共享内存的地址。
int flag
:flag是一组标志位,通常为0。
调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.
3.断开当前进程与共享内存的映射
不使用删除而使用断开的原因是因为:也许还存在其他的进程会继续使用这块共享内存
int shmdt(const void *addr);
4.操作共享内存的方法
int shmctl(int shmid, int cmd, struct shmid_t *buf);
int shmid
:shmid是shmget()函数返回的共享内存标识符。
int cmd
:command是要采取的操作,它可以取下面的三个值 :
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID:删除共享内存段
struct shmid_t *buf
:buf是一个结构指针,它指向共享内存模式和访问权限的结构
因为有连接计数器,除非最后一个进程与该共享段断开连接,则删除该共享段。否则,并不会真正删除该共享段,但是共享内存的内核对象会被立即删除,不能使用shmat方法与该段连接。
一个进程调用该方法删除后,不会影响之前已经和该共享存储段连接的进程
下面我们利用共享内存来进行一个简单的测试:
完成下面的过程,
成功在共享内存中读到了数据
#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> #include<unistd.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> #include"sem.h" #define READSEM 1 #define WRITESEM 0 int main() { int shmid = shmget((key_t)1234,128,0664 | IPC_CREAT); assert(shmid != -1); char *ptr = (char*)shmat(shmid,NULL,0); assert(ptr != (char*)-1); int initVal[] = {1,0}; int semid = SemGet(1234,intVal,2); assert(semid != -1); //A进程写 while(1) { SemP(semid,WRITESEM); printf("Input:"); fgets(ptr,127,stdin); SemV(semid,READSEM); if(strncmp(ptr,"end",3) == 0) { break; } } shmdt(ptr); exit(0); }
#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> #include<unistd.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> #include"sem.h" #define READSEM 1 #define WRITESEM 0 int main() { int shmid = shmget((key_t)1234,128,0664 | IPC_CREAT); assert(shmid != -1); char *ptr = (char*)shmat(shmid,NULL,0); assert(ptr != (char*)-1); int initVal[] = {1,0}; int semid = SemGet(1234,intVal,2); assert(semid != -1); //B进程读 while(1) { SemP(semid,READSEM); if(strncmp(ptr,"end",3) == 0) { break; } int i = 0; for(;i < strlen(ptr) - 1;i++) { printf("%c",toupper(ptr[i])); fflush(stdout); sleep(1); } printf("\n"); SemV(semid,WRITESEM); } shmdt(ptr); exit(0); }
从上面的代码中我们可以看出:
共享内存是最快的IPC,在通信过程中少了两次数据的拷贝。(相较于管道)
查看 ipcs -m
删除 ipcrm -m shmid
Das obige ist der detaillierte Inhalt vonSo implementieren Sie die prozessübergreifende Linux-Kommunikation. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!