c общая память присоединение / отсоединение / освобождение - PullRequest
4 голосов
/ 05 января 2012

У меня есть вопрос относительно сегментации разделяемой памяти в c с использованием системных вызовов POSIX. Это правильно, что я отсоединяю и удаляю сегмент от клиента и сервера или мне просто нужно удалить с сервера?

Считайте, что у меня есть 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;
}

1 Ответ

6 голосов
/ 05 января 2012

Поскольку вы используете System V IPC, а не POSIX IPC, проверьте значение shm_nattch в структуре данных, связанной с идентификатором сегмента разделяемой памяти. Вы можете получить это значение, вызвав shmctl с флагом IPC_STAT. Вызов shmdt уменьшит это значение на единицу, и последний процесс, который вызовет эту функцию, установит значение shm_nattach в 0. После обнуления значения вы можете безопасно позвонить на shmctl, чтобы удалить сегмент памяти.

Таким образом, в коде вашего клиента и сервера, если сервер не гарантированно переживет клиента, вы должны проверить значение shm_nattch с отдельным вызовом shmctl после вызова shmdt, чтобы узнать, является ли число процессы, обращающиеся к сегменту разделяемой памяти, сведены к нулю. Вы также должны убедиться в том, что проверили на ошибки результаты этого вызова IPC_STAT, чтобы избежать состояния гонки, когда два отдельных процесса вызывают shmdt, уменьшая значение shm_nattch до нуля, но процесс, который был на самом деле последний вызов shmdt приостанавливается операционной системой, а другой процесс видит значение shm_nattch равным нулю и удаляет сегмент памяти. Поскольку для проверки и удаления сегмента совместно используемой памяти требуются вызовы shm_ctl, и этот вызов не будет выполнен, если идентификатор сегмента совместно используемой памяти недействителен, теоретически не следует сталкиваться с какими-либо условиями гонки, если вы только совершает вызовы shm_ctl или shmdt после того, как один процесс удалил сегмент совместно используемой памяти. Однако вам следует избегать доступа к указателю на сегмент общей памяти после его удаления. Проверка неудавшихся звонков на shm_ctl поможет вам избежать подобных ситуаций. Другими словами, если вызов не удался, вы больше не сможете безопасно обращаться к указателю.

Если, с другой стороны, ваш сервер гарантированно переживет любого из клиентов, то сервер может безопасно выполнить вызов для удаления сегмента общей памяти, поскольку он будет последним процессом, использующим его ... все другим клиентам не нужно удалять сегмент памяти, а просто отсоединять от него.

...