我对使用POSIX系统调用的c中的共享内存分段有疑问。我是从客户端和服务器分离和删除段,还是只需要从服务器中删除它?
考虑我有2个程序
一个用于服务器,一个用于客户端
the steps for the server
1)create memory segment
2)attach
3)detach
4)remove
steps for the client
1)create
2)attach
3)detach
4)remove
这是我的代码:
//server
#include<stdlib.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/shm.h>
#define SHMSZ 100
int main()
{
key_t key;
char c;
int shmid;
char *shm;
key=1025;
//locate
if((shmid=shmget(key,SHMSZ,0666 | IPC_CREAT))<0)
{
perror("shmget");
exit(-1);
}
//attach
if((shm=shmat(shmid,NULL,0))==(char*)-1)
{
perror("shmat");
exit(-1);
}
sprintf(shm,"Hi there");
//shm="Hi There";
while(*shm!='*');
sleep(1);
//detach
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
这是客户端
//client
#include<stdlib.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/shm.h>
#define SHMSZ 100
int main()
{
key_t key;
int shmid;
char c;
char *shm, *s;
key=1025;
//locate
if((shmid=shmget(key,SHMSZ,0666 | IPC_CREAT))<0)
{
perror("shmget");
exit(-1);
}
//attach
if((shm=shmat(shmid,NULL,0))==(char*)-1)
{
perror("shmat");
exit(-1);
}
printf("%s\n",shm);
*shm='*';
shmdt(&shmid);
shmctl(shmid, IPC_RMID,NULL);
return 0;
}
答案 0 :(得分:6)
由于您使用的是System V IPC而不是POSIX IPC,因此请检查与共享内存段ID相关联的数据结构中shm_nattch
的值。您可以通过使用shmctl
标记调用IPC_STAT
来获取此值。调用shmdt
会将此值减一,调用此函数的最后一个过程会将shm_nattach
的值设置为0
。一旦值清零,您就可以安全地调用shmctl
来删除内存段。
因此,在客户端和服务器代码中,如果服务器不能保证服务器的使用寿命,则应在调用shm_nattch
后单独调用shmctl
来检查shmdt
的值。查看访问共享内存段的进程数是否已减少到零。您还应确保对此IPC_STAT
调用的结果进行错误检查,以避免因两个单独的进程调用shmdt
而将shm_nattch
的值减小为零的竞争条件,但是实际上最后调用shmdt
的进程被OS挂起,而另一个进程看到shm_nattch
的值为零并删除了内存段。由于检查和删除共享内存段都需要调用shm_ctl
,如果共享内存段的ID无效,则该调用将失败,理论上如果你仅在单个进程删除共享内存段后调用shm_ctl
或shmdt
。您想要避免的事情是在删除之后访问指向共享内存段的指针。检查shm_ctl
的失败呼叫将帮助您避免这些类型的情况。换句话说,如果调用失败,那么你就不能再安全地访问指针了。
如果另一方面,您的服务器保证比任何客户端寿命长,那么服务器可以安全地进行调用以删除共享内存段,因为它将是使用它的最后一个进程...所有其他客户端不需要删除内存段,只需从中删除即可。