2) 使用key来创建一个共享内存 shmget() 3) 映射共享内存(得到虚拟地址), shmat() 4) 使用共享内存, 往共享内存中写入数据 5) 解除映射 shmdt key来获得一个共享内存 shmget() 3) 映射共享内存(得到虚拟地址), shmat() 4) 使用共享内存, 读取共享内存中的数据 5) 解除映射 shmdt 写共享内存 int *pp = p; *pp = 0x12345678; *(pp + 1) = 0xffffffff; // 解除映射 if(-1 == shmdt (p)) { perror("shmdt failed"); exit(3); } printf("解除映射成功,点击回车销毁共享内存\n"); (p)) { perror("shmdt failed"); exit(3); } return 0; } 运行结果: writeshma:
unsigned long int __glibc_reserved1; #endif __time_t shm_dtime; /* time of last shmdt 共享内存的分离 当进程使用完共享内存后,需要将共享内存从其进程空间中去除(detach),使用shmdt()函数: #include <sys/types,h> #include <sys/ipc.h> #include <sys/shm.h> int shmdt(void *addr); 运行成功返回0,出错返回-1。 shmdt()函数执行成功后,shm_nattch计数器值减1。 (p) == -1) { perror("shmdt failed"); exit(3); } // delete the share memory
time */ pid_t shm_cpid; /* PID of creator */ pid_t shm_lpid; /* PID of last shmat(2)/shmdt key_t key, size_t size, int shmflg); void *shmat(int shmid, const void *shmaddr, int shmflg); int shmdt 公式:shmaddr - (shmaddr % SHMLBA) shmflg=SHM_RDONLY,表示连接操作用来只读共享内存 功能:将共享内存段与当前进程脱离 原型 int shmdt(const (p == (void *) - 1) ERR_EXIT("shmat"); strcpy(p->name, "lisi"); p->age = 20; shmdt (void *) - 1) ERR_EXIT("shmat"); printf("name = %s age = %d\n", p->name, p->age); shmdt
if (strncmp(shmadd->text, "quit", 4) == 0) { sleep(1); if (shmdt (shmadd) == -1) { perror("shmdt"); } if (shmctl(shmid %s\n", shmadd->text); if (strncmp(shmadd->text, "quit", 4) == 0) { if (shmdt (shmadd) == -1) { perror("shmdt"); } exit(0);
当进程结束使用共享内存区时,要通过函数 shmdt 断开与共享内存区的连接。 该函数声明在 sys/shm.h 中,其原型如下: int shmdt(const void *shmaddr); 参数 shmaddr 是 shmat 函数的返回值。 Shmdt和shmctl的区别: Shmdt 是将共享内存从进程空间detach出来,使进程中的shmid无效化,不可以使用。但是保留空间。
* * @param - shmaddr: the addr of the System V shared memory * * @return On success, shmdt() returns 0; * on error -1 is returned, and errno is set to indicate the cause of * the error. */ int shmdt \n"); if (shmdt(shm) == -1) { printf("shmdt failed! 1; if (strncmp(buffer, "end", 3) == 0) { running = 0; } } if (shmdt (shm) == -1) { printf("shmdt failed!
返回值: 成功:返回映射地址 失败:返回(void*)-1 3.shmdt 函数原型:int shmdt(const void *shmaddr); 功能:断开当前进程虚拟地址空间与shmaddr指向的共享内存的映射 参数shmaddr:指向共享内存的指针 需要注意的是shmdt并不能进行共享内存区域的删除。需要使用shmctl或者ipcrm进行删除。 ) { printf("input: "); fgets(p, PAGESIZE-1, stdin); if (strncmp(p, "end", 3) == 0) break; } shmdt char*)-1); while (1) { if (strncmp(p, "end", 3) == 0) break; printf("%s ", p); sleep(1); } shmdt
相关参考: shmat 函数的使用 ---- shmdt 作用:取消共享内存映射 函数原型:int shmdt(const void *shmaddr); 参数: shmaddr:由shmat 相关参考: shmdt-Linux API速查手册 ---- shmctl 作用: 用于控制共享内存。 = 0; while((i++) < 50){ p->count++; sleep(1); } //把共享内存从当前进程中分离 if(shmdt (shm) == -1){ fprintf(stderr, "shmdt failed\n"); exit(3); } return 0; } shmread.c #include < printf("ip = %s ,count: %d\t\t\n", stat->ip, stat->count); sleep(1); } //把共享内存从当前进程中分离 if(shmdt
(3)第三个参数,shm_flg是一组标志位,通常为0 3.4分离操作———>shmdt()函数 该操作不从系统中删除标识符和其数据结构,要显示调用shmctl(带命令IPC_RMID)才能删除它 int shmdt(const void *shmaddr); //成功返回0,出错返回-1 (1)addr参数是以前调用shmat时的返回值 4.模拟实现进程间的通信方式———>共享内存 Server作为发送方 Destory"); return -2; } return 0; } '; sleep(1); } if(shmdt printf("%s\n",addr); sleep(1); i++; } if(shmdt (addr)==-1) { perror("shmdt"); return-1; } }
2 .实验内容 (1) 了解系统调用pipe()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程。 (2) 编写一段程序,使其用管道来实现父子进程之间的进程通信。 3 .实验步骤 (1) 了解系统调用pipe()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程。 pipe()创建一条管道进行信息传输。 得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符 shmat()连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问 shmdt ; printf("%s\n",message); addr=shmat(id,0,0); strcpy(addr,message); shmdt addr); }else{ wait(0); addr=shmat(id,0,0); printf("%s\n",addr); shmdt
;std::cout<<"数据已写入共享内存"<<std::endl;//分离共享内存(但不删除)shmdt(shared_memory);return0;}第三步:读取共享内存数据展开代码语言:C++ shared_memory=(char*)shmat(shmid,nullptr,0);std::cout<<"从共享内存读取:"<<shared_memory<<std::endl;//分离共享内存shmdt sprintf(str,"消息%d",i);std::cout<<"写入:"<<str<<std::endl;sleep(2);//等待2秒}//写入结束标志strcpy(str,"结束");//分离共享内存shmdt std::cout<<"读取:"<<str<<std::endl;//检查是否收到结束标志if(strcmp(str,"结束")==0){break;}sleep(1);//每秒检查一次}//分离共享内存shmdt
} PGShmemHeader; IPC的共享内存使用分为三步: 申请:shm_id申请共享内存段,申请后可以使用ipcs -m查询 关联:shmat将共享内存映射到自己的内存空间中 解除关联:shmdt "segment size:%ld\n", shmbuffer.shm_segsz); sprintf(memAddress, "Hello,world."); /* detaches */ shmdt 0); printf("shared memory reattched at address %p\n", memAddress); printf("%s\n", memAddress); shmdt
使用shmdt来解除绑定,其中dt代表单词delete。 shmdt的声明: int shmdt(const void *shmaddr); 参数shmaddr:需要断开连接的共享内存的起始地址。 一个共享内存,与它绑定的程序的个数是由一个引用计数机制进行维护的,当shmdt成功,引用计数减1。 只有当所有附加的进程都调用 shmdt 分离后,系统才会释放资源。 nullptr, 0); if ((long long)_start_mem < 0) { ERROR("shmat"); } } void Destroy() { int m = shmdt (_start_mem); if (m < 0) { ERROR("shmdt"); } int n = shmctl(_shmid, IPC_RMID, nullptr);
2.4 shmdt函数 shmdt用于将共享内存段与进程空间分离,与shmat函数相反。用于关闭共享内存段。 #include <sys/types.h> #include <sys/shm.h> int shmdt(const void *shmaddr); 参数 shmaddr通常为shmat的成功返回值 往共享内存段中写入内容 shmdt(p); //5. 取消映射*/ shmdt(p); return 0; } 4.2 打开内存读数据示例 #include <stdio.h> #include <unistd.h> #include <string.h 取消映射*/ shmdt(p); /*5. 释放共享内存空间*/ shmctl(shmid,IPC_RMID,NULL); return 0; }
二:系统V共享内存API 对于系统V共享内存,主要有以下几个API:shmget()、shmat()、shmdt()及shmctl()。 shmdt()调用用来解除进程对共享内存区域的映射。shmctl实现对共享内存区域的控制操作。 三:实例 两个进程通过系统V共享内存通信的范例。 ;//对共享内存写操作(就是在进程的映射内存里写), (*(p_map+i)).age=20+i;//(*(p_map+i)).name等同于(p_map+i)->name } if(shmdt shmdt() 5.删除这块共享内存 shmctl()或者命令行下ipcrm ftok():它有两个参数,一个是字符串,一个是字符。 shmdt( head ); // 禁止本进程使用这块内存 此外,还有一个用来控制共享内存的shmctl()函数如下: #include <sys/types.h> #include <sys/ipc.h
shmid, int cmd, struct shmid_ds *buf); void *shmat(int shmid, const void *shmaddr, int shmflg); int shmdt 之后我们就可以对对应的内存空间进行操作了: *shm_p = 100; if (shmdt(shm_p) < 0) { perror("shmdt()"); IPC_RMID, NULL) < 0) { perror("shmctl()"); exit(1); } return 0; 在使用完共享内存之后,需要使用int shmdt shmdt仅仅只是解除共享内存空间和进程地址的映射,而想要删除一个共享内存需要使用int shmctl(int shmid, int cmd, struct shmid_ds *buf)函数进行处理同时也可以在命令行中使用第二小节的
1.2.3 shmdt()函数 函数原型: int shmdt(const void *shmaddr); 功能: shmdt 是 System V IPC(进程间通信)中的一个系统调用,用于 调用 shmdt 后,进程不能再通过该地址访问共享内存。 参数: shmaddr:指向共享内存的起始地址,通常是通过 shmat 返回的地址。它是指向共享内存区域的指针。 注意事项: 共享内存的删除:shmdt 只是从进程的地址空间中分离共享内存,并不会删除共享内存段。如果共享内存不再需要,可以使用 shmctl 函数来删除共享内存段。 多进程共享内存:当多个进程共享同一块内存时,每个进程在完成共享内存的操作后,都应调用 shmdt 来分离共享内存。如果不再需要共享内存,最终应通过 shmctl 删除共享内存段。 清理:在分离共享内存后,如果其他进程仍然附加该共享内存,系统不会立即删除共享内存,直到最后一个进程调用 shmdt并且没有其他进程附加它时,才会被完全清理。
*/ if (shmdt(shm_p) < 0) { perror("shmdt()"); exit(1); } exit(0); } int */ if (shmdt(shm_p) < 0) { perror("shmdt()"); exit(1); } /* 删除共享内存。 当然,在使用之后要记得使用shmdt解除映射,否则对于长期运行的程序可能造成虚拟内存地址泄漏,导致没有可用地址可用。 shmdt并不能删除共享内存段,而只是解除共享内存和进程虚拟地址的映射,只要shmid对应的共享内存还存在,就仍然可以继续使用shmat映射使用。 实际上共享内存的生存周期根文件更像:进程对文件描述符执行close并不能删除文件,而只是关闭了本进程对文件的操作接口,这就像shmdt的作用。
EINTR:当睡眠时接收到其他信号 EINVAL:信号量集不存在,或者semid无效 ENOMEM:使用了SEM_UNDO,但无足够的内存创建所需的数据结构 ERANGE:信号量值超出范围 ---- shmdt sys/shm.h 中有关于 shmdt 的原型声明 /* Detach shared memory segment. */ extern int shmdt (__const void *__shmaddr 32 unsigned long int __unused1; #endif __time_t shm_dtime; /* time of last shmdt long int __unused1; unsigned long int __unused2; }; ---- 总结 以下函数可以进行信号量和共享内存的创建与控制 shmget shmat shmdt
文件锁 (fcntl) 分离共享内存段 (shmdt): 当进程不再需要访问共享内存时,调用 shmdt(const void *shmaddr)。 当最后一个使用该段的进程分离 (shmdt) 之后,内核才会真正销毁该段并回收资源。 即使所有进程都已分离,但只要没有调用 IPC_RMID,段依然存在(可能造成资源泄漏)。 4.3 shmdt 函数:断开共享内存连接 功能:将共享内存段从当前进程的地址空间分离(解除映射),但不会删除共享内存。 卸载(模拟 shmdt): 同样需在进程内部触发,无直接命令替代。可通过终止进程自动卸载(进程退出时会自动调用shmdt)。 去关联:shmdt(shmaddr) 解除映射 。 控制操作:shmctl(shmid, IPC_RMID, NULL) 删除共享内存 。