c共享内存附加/分离/解除分配

myd*_*dsl 4 c client posix shared-memory

我对使用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
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

//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;
}
Run Code Online (Sandbox Code Playgroud)

这是客户端

//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;
}
Run Code Online (Sandbox Code Playgroud)

Jas*_*son 6

由于您使用的是System V IPC而不是POSIX IPC,因此请检查shm_nattch与共享内存段ID相关联的数据结构中的值.你可以通过调用shmctl标志来获得这个值IPC_STAT.呼叫shmdt将由一个减小此值,最后过程调用这个函数将设置的值shm_nattach0.一旦值清零,您就可以安全地调用shmctl以删除内存段.

因此,在客户端和服务器代码中,如果服务器不能保证比客户端寿命长,则应在shm_nattch调用shmctl之后检查单独调用的值,shmdt以查看访问共享内存段的进程数是否已减少到零.您还应确保对此IPC_STAT调用的结果进行错误检查,以避免两个独立进程调用的竞争条件shmdt,将值减小shm_nattch为零,但shmdt操作系统暂停实际上最后一次调用的进程,另一个进程看到值shm_nattch为零并删除内存段.由于检查和删除共享内存段都需要调用shm_ctl,如果共享内存段的ID无效,调用将失败,理论上如果您调用shm_ctlshmdt之后调用,则理论上不应该遇到任何竞争条件单个进程已删除共享内存段.您想要避免的事情是在删除之后访问指向共享内存段的指针.检查失败的呼叫shm_ctl将帮助您避免这些类型的情况.换句话说,如果调用失败,那么您将无法再安全地访问指针.

如果另一方面,您的服务器保证比任何客户端寿命长,那么服务器可以安全地进行调用以删除共享内存段,因为它将是使用它的最后一个进程...所有其他客户端将不需要删除内存段,只需从中分离即可.