【问题标题】:c shared memory attach/detach/deallocatec 共享内存附加/分离/解除分配
【发布时间】:2012-02-02 18:22:51
【问题描述】:

我对使用 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;
}

【问题讨论】:

    标签: c client posix shared-memory


    【解决方案1】:

    由于您使用的是 System V IPC 而不是 POSIX IPC,请检查与共享内存段 ID 关联的数据结构中的 shm_nattch 的值。您可以通过调用带有IPC_STAT 标志的shmctl 来获取此值。调用shmdt会将该值减一,最后调用该函数的进程会将shm_nattach的值设置为0。将值清零后,您可以安全地调用 shmctl 以删除内存段。

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

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

    【讨论】:

    • 感谢您的澄清,您的意思是 shmctl(shmid,IPC_STAT,NULL) 在我的情况下?
    • 不要将NULL 作为第三个参数传递...您需要传递本地struct shmid_ds 类型的地址,然后您可以使用它来检查shm_nattch 的值.
    • 是不是类似 int ret; ret=shmctl(shmid, IPC_STAT, (struct shmid_ds*)&shmid); if(ret) { fprintf(stderr,"error"); }
    • 不要将您的 ID 值转换为 shmid_ds 结构......它们根本不是一回事。如果您决定要使用strerror(),您还可以使用perror()strerror(errno) 访问错误类型,并在代码模块中包含errno.h 和/或string.h。例如,如果您调用shm_ctl 返回-1,则可以执行fprintf(stderr, "%s", strerror(errno));
    猜你喜欢
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    相关资源
    最近更新 更多