Reputation: 568
I have question regarding shared memory segmentation in c using POSIX system calls. Is it right that I am detaching and removing segment from client and server or i just need to remove from server?
Consider I have 2 programmes
One for server and one for client
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
this is my code:
//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;
}
this is client side
//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;
}
Upvotes: 4
Views: 4988
Reputation: 32538
Since you're using System V IPC rather than POSIX IPC, check the value of shm_nattch
in the data-structure associated with the ID of the shared memory segment. You can get this value by calling shmctl
with a flag of IPC_STAT
. Calling shmdt
will reduce this value by one, and the last process to call this function will set the value of shm_nattach
to 0
. Once the value is zeroed-out, you can safely make a call to shmctl
to remove the memory segment.
So in both your client and server code if the server is not guaranteed to outlive a client, you should check the value of shm_nattch
with a separate call to shmctl
after calling shmdt
to see if the number of processes accessing the shared memory segment has been reduced to zero. You should also make sure to error-check the results of this IPC_STAT
call in order to avoid a race-condition where two separate processes call shmdt
, reducing the value of shm_nattch
to zero, but the process that was actually the last to call shmdt
is suspended by the OS, and the other process sees the value of shm_nattch
is zero and removes the memory segment. Since both checking and removing the shared memory segment requires calls to shm_ctl
, and that call will fail if the ID of the shared-memory segment is invalid, you theoretically shouldn't run into any race-conditions if you only make calls to shm_ctl
or shmdt
after a single process has removed the shared memory segment. The thing you want to avoid though would be accessing a pointer to the shared memory segment after it's been removed. Checking for failed calls to shm_ctl
will help you avoid those types of situations. In other words if the call fails, then you can't safely access the pointer anymore.
If on the other-hand your server is guaranteed to outlive any of the clients, then the server can safely make the call to remove the shared memory segment, since it will be the last process using it ... all of the other clients will not need to remove the memory segment, but simply detach from it.
Upvotes: 6