|
Home > Archive > Unix Programming > December 2006 > How to write a structure that has pointers in the shared memory?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
How to write a structure that has pointers in the shared memory?
|
|
| barkha 2006-12-19, 7:25 pm |
| Hi All,
I want a help on some piece of code that can demonstrate how to wrtie
this structure in the shared memory? I have some child processes that
are going to write these structures in the shared memory and parent
process is suppose to pull these structures out of the shared memory.
typedef struct AgentReq {
int command;
short numParms;
short maxParms;
int requestType;
const void **parm;
int *parmType;
int *parmLen;
} AgentReq;
PS: The structure is already allocated from heap and the data members
are already populated. Now they need to be put in the shared memory by
all the child processess who are working on this structure.
Uptill now in my current architecture ,child processes used to
communicate with the parent process about the above structure using the
TCP/IP socket. Parent process used to listen on localhost : <someport>
and child processes used to send these structures one by one to the
parent process using socket.
Now I want to avoid opening the socket for communication between child
and parent process and henceforth want to make use of shared memory.
This topic has nothing to do with any platform. It has more to do with
teaching me how to read and write the above structure in the shared
memory. I have learned that shared memory should never contain pointers
and Instead of pointers one should write offset in bytes from
start of shared memory. I want to know HOW? Can anyone please explain
me in terms of C language?
A quick help on this will be appreciated.
Thanks.
| |
| barkha 2006-12-19, 7:25 pm |
| thanks for giving another alternate solution. But I am afraid I need to
know the answer to the particular question only.
Rob Hoelz wrote:
> "barkha" <barkhashah@gmail.com> wrote:
>
>
> Well, since you're using parent and child processes, you could (and
> probably should) use pipes to communicate data between them. Check the
> man page for popen to see how.
> --
> -Rob Hoelz
| |
| Pascal Bourguignon 2006-12-19, 7:25 pm |
| "barkha" <barkhashah@gmail.com> writes:
> Hi All,
> I want a help on some piece of code that can demonstrate how to wrtie
> this structure in the shared memory? I have some child processes that
> are going to write these structures in the shared memory and parent
> process is suppose to pull these structures out of the shared memory.
>
> typedef struct AgentReq {
> int command;
> short numParms;
> short maxParms;
> int requestType;
> const void **parm;
> int *parmType;
> int *parmLen;
> } AgentReq;
>
> [...]
> I have learned that shared memory should never contain pointers
> and Instead of pointers one should write offset in bytes from
> start of shared memory. I want to know HOW? Can anyone please explain
> me in terms of C language?
> A quick help on this will be appreciated.
Well, one problem is that you don't specify what parm parmType and
ParmLen are.
So let me take another example.
/* pseudo-code */
/* We have a binary tree of nodes, without cycles!
If we had cycles in the data structure, we'd have to implement a
more complex algorithm, using two phases, or keeping track of the
nodes already stored in the shared memory. */
typedef struct node {
int data;
struct item* pointer_to_left;
struct item* pointer_to_right;
} node_t;
const int null_offset=1;
typedef struct shared_node {
int data;
int offset_to_left;
int offset_to_right;
} shared_node_t;
void* copy_nodes_to_shared_memory(item_t* tree,void* shared_base,int shared_size){
shared_item_t* shared=shared_base;
if(tree==NULL){
return(null_offset);
}else if(sizeof(*shared)<=shared_size){
shared_base=((char*)shared_base)+sizeof(
*shared);
shared_size-=sizeof(*shared);
shared->data=tree->data;
if(tree->pointer_to_left==NULL){
shared->offset_to_left=null_offset;
}else{
void* new;
shared->offset_to_left=((char*)shared_base)-((char*)shared);
new=copy_nodes_to_shared_memory(tree->pointer_to_left,
shared_base,shared_size);
shared_size-=((char*)new)-((char*)shared_base);
shared_base=new;
}
if(tree->pointer_to_right==NULL){
shared->offset_to_right=null_offset;
}else{
void* new;
shared->offset_to_right=((char*)shared_base)-((char*)shared);
new=copy_nodes_to_shared_memory(tree->pointer_to_right,
shared_base,shared_size);
shared_size-=((char*)new)-((char*)shared_base);
shared_base=new;
}
return(shared_base);
}else{
error("Not enought space in shared memory.");
}
}
/* Exercise left to the reader:
node_t* copy_nodes_from_shared_memory(void* shared_base);
*/
/* Or, instead of copy_nodes_from_shared_memory, we can directly use
the data in the shared memory:
*/
int node_data(shared_node_t* node){
return(node->data);
}
shared_node_t* node_left(shared_node_t* node){
return((shared_node_t*)(((char*)node)+no
de->offset_to_left));
}
shared_node_t* node_right(shared_node_t* node){
return((shared_node_t*)(((char*)node)+no
de->offset_to_right));
}
/* Basically, one can implement one's own memory manager inside the
shared memory block, and allocate and free data blocks in it, using
offset everywhere a pointer would be stored.
(shared_malloc and shared_free left as an exercise to the reader).
Of course, since the location of the pointers depends on the data
structure, one needs to write accessor functions for each type of
structure allocated in the shared memory.
*/
void set_node_data(shared_node_t* node,int data){
node->data=data;
}
void set_node_left(shared_node_t* node,shared_node_t* new_left){
node->offset_to_left=((char*)new_left)-((char*)node);
}
void set_node_right(shared_node_t* node,shared_node_t* new_right){
node->offset_to_right=((char*)new_right)-((char*)node);
}
--
__Pascal Bourguignon__ http://www.informatimago.com/
Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.
| |
| barkha 2006-12-20, 1:39 am |
| Thanks Pascal. The sample is a very good insight to get me started.
I would request you to also explain me the dynamics behind these
addition and subtraction that you are doing with the pointers.
I want to understand how these offsets are manintained? What are they?
shared_base=((char*)shared_base)+sizeof(
*shared);
To elaborate on the structure:
const void ** parm could further contain array of any other structure
type which will have pointer variables in it.
Pascal Bourguignon wrote:[vbcol=seagreen]
> "barkha" <barkhashah@gmail.com> writes:
>
>
> Well, one problem is that you don't specify what parm parmType and
> ParmLen are.
>
> So let me take another example.
>
> /* pseudo-code */
>
> /* We have a binary tree of nodes, without cycles!
> If we had cycles in the data structure, we'd have to implement a
> more complex algorithm, using two phases, or keeping track of the
> nodes already stored in the shared memory. */
>
> typedef struct node {
> int data;
> struct item* pointer_to_left;
> struct item* pointer_to_right;
> } node_t;
>
>
> const int null_offset=1;
>
> typedef struct shared_node {
> int data;
> int offset_to_left;
> int offset_to_right;
> } shared_node_t;
>
> void* copy_nodes_to_shared_memory(item_t* tree,void* shared_base,int shared_size){
> shared_item_t* shared=shared_base;
> if(tree==NULL){
> return(null_offset);
> }else if(sizeof(*shared)<=shared_size){
> shared_base=((char*)shared_base)+sizeof(
*shared);
> shared_size-=sizeof(*shared);
> shared->data=tree->data;
> if(tree->pointer_to_left==NULL){
> shared->offset_to_left=null_offset;
> }else{
> void* new;
> shared->offset_to_left=((char*)shared_base)-((char*)shared);
> new=copy_nodes_to_shared_memory(tree->pointer_to_left,
> shared_base,shared_size);
> shared_size-=((char*)new)-((char*)shared_base);
> shared_base=new;
> }
> if(tree->pointer_to_right==NULL){
> shared->offset_to_right=null_offset;
> }else{
> void* new;
> shared->offset_to_right=((char*)shared_base)-((char*)shared);
> new=copy_nodes_to_shared_memory(tree->pointer_to_right,
> shared_base,shared_size);
> shared_size-=((char*)new)-((char*)shared_base);
> shared_base=new;
> }
> return(shared_base);
> }else{
> error("Not enought space in shared memory.");
> }
> }
>
>
> /* Exercise left to the reader:
>
> node_t* copy_nodes_from_shared_memory(void* shared_base);
>
> */
>
>
>
>
> /* Or, instead of copy_nodes_from_shared_memory, we can directly use
> the data in the shared memory:
> */
>
> int node_data(shared_node_t* node){
> return(node->data);
> }
>
> shared_node_t* node_left(shared_node_t* node){
> return((shared_node_t*)(((char*)node)+no
de->offset_to_left));
> }
>
> shared_node_t* node_right(shared_node_t* node){
> return((shared_node_t*)(((char*)node)+no
de->offset_to_right));
> }
>
>
>
> /* Basically, one can implement one's own memory manager inside the
> shared memory block, and allocate and free data blocks in it, using
> offset everywhere a pointer would be stored.
> (shared_malloc and shared_free left as an exercise to the reader).
>
> Of course, since the location of the pointers depends on the data
> structure, one needs to write accessor functions for each type of
> structure allocated in the shared memory.
> */
>
> void set_node_data(shared_node_t* node,int data){
> node->data=data;
> }
>
> void set_node_left(shared_node_t* node,shared_node_t* new_left){
> node->offset_to_left=((char*)new_left)-((char*)node);
> }
>
> void set_node_right(shared_node_t* node,shared_node_t* new_right){
> node->offset_to_right=((char*)new_right)-((char*)node);
> }
>
>
>
>
>
> --
> __Pascal Bourguignon__ http://www.informatimago.com/
>
> Nobody can fix the economy. Nobody can be trusted with their finger
> on the button. Nobody's perfect. VOTE FOR NOBODY.
| |
| Pascal Bourguignon 2006-12-20, 1:39 am |
| "barkha" <barkhashah@gmail.com> writes:
> Thanks Pascal. The sample is a very good insight to get me started.
> I would request you to also explain me the dynamics behind these
> addition and subtraction that you are doing with the pointers.
> I want to understand how these offsets are manintained? What are they?
They are the difference between the pointer to the current structure
and the pointer to the "pointed to" structure.
One could also compute the offset relatively to the address where the
offset is stored:
structure->offset=((char*)pointer)-((char*)&(structure->offset));
and back:
pointer=(void*)(((char*)&(structure->offset))+structure->offset);
Or they could be all computed from the beginning of the shared memory:
structure->offset=((char*)pointer)-((char*)shared_memory_base);
and back:
pointer=(void*)(((char*)shared_memory_ba
se)+structure->offset);
Your choice.
> shared_base=((char*)shared_base)+sizeof(
*shared);
Here, I "allocate" the shared structure in the shared memory pointed
to by shared_base.
--
__Pascal Bourguignon__ http://www.informatimago.com/
PLEASE NOTE: Some quantum physics theories suggest that when the
consumer is not directly observing this product, it may cease to
exist or will exist only in a vague and undetermined state.
| |
| Nils O. Selåsdal 2006-12-20, 7:24 am |
| barkha wrote:[vbcol=seagreen]
> thanks for giving another alternate solution. But I am afraid I need to
> know the answer to the particular question only.
>
> Rob Hoelz wrote:
Just use ordinary structure coopying by the means of the = operator.
void *shmptr = shmat(....);
AgentReq *smhagent = shmptr;
shmagent = *youragentptr;
Nothing more to it. Except, your structure contains pointers,
which also needs to be places somewhere in the shared memory
segment.
If parmType is an array, let's place it after the structure
and adjust the pointer.
memcpy((unsigned char *)shmptr + sizeof smhagent ,youragentptr->parmType
,N * sizeof youragentptr->parmType);
smhagent->parmType = (int*)((unsigned char *)shmptr + sizeof smhagent);
You might need a syncronization mechanism to tell clients when you've
finished updating things in the shared segment, so they can safely
start woring on it. Be sure they don't step on eachothers toes too.
| |
| Nils O. Selåsdal 2006-12-20, 7:24 am |
| Nils O. Selåsdal wrote:
> barkha wrote:
> Just use ordinary structure coopying by the means of the = operator.
> void *shmptr = shmat(....);
> AgentReq *smhagent = shmptr;
> shmagent = *youragentptr;
Managed to get the line of interest wrong, sorry about that. The above
should naturally be
*shmagent = *youragentptr;
| |
| barkha 2006-12-20, 7:21 pm |
| Thanks everyone for throwing light on this topic.
I have another question. I dont know if its a right place to post in.
If I just want to store array of characters , say
char str[100]
and the size of str can vary most of the time. Say there are many child
processes who are going to write different strings of different sizes
into the shared memory, how do I decide how much big size of shared
memory I may be required.
Its possible that child processes would keep writing into the buffer
and parent process may also read them simoultaneously and remove it
from the shared memory, but during corner cases , its likely that child
processes (producer) writes into the shared memory faster than the
parent process (consumer) can consume it and very soon fills up the
shared memory. In that case can shared memory be expanded?
So in nutshell 2 questions:
1) How best to determine the maximum size of the file mapping object
when we have multiple child processes coming and writing into the
shared memory with varying string sizes.
2) Can shared memory be expanded later once it gets full?
Thanks
Pascal Bourguignon wrote:
> "barkha" <barkhashah@gmail.com> writes:
>
>
> They are the difference between the pointer to the current structure
> and the pointer to the "pointed to" structure.
>
> One could also compute the offset relatively to the address where the
> offset is stored:
>
> structure->offset=((char*)pointer)-((char*)&(structure->offset));
>
> and back:
>
> pointer=(void*)(((char*)&(structure->offset))+structure->offset);
>
>
> Or they could be all computed from the beginning of the shared memory:
>
> structure->offset=((char*)pointer)-((char*)shared_memory_base);
>
> and back:
>
> pointer=(void*)(((char*)shared_memory_ba
se)+structure->offset);
>
>
> Your choice.
>
>
>
> Here, I "allocate" the shared structure in the shared memory pointed
> to by shared_base.
>
>
> --
> __Pascal Bourguignon__ http://www.informatimago.com/
>
> PLEASE NOTE: Some quantum physics theories suggest that when the
> consumer is not directly observing this product, it may cease to
> exist or will exist only in a vague and undetermined state.
| |
| Pascal Bourguignon 2006-12-21, 1:29 am |
| "barkha" <barkhashah@gmail.com> writes:
> Thanks everyone for throwing light on this topic.
> I have another question. I dont know if its a right place to post in.
>
> If I just want to store array of characters , say
> char str[100]
>
> and the size of str can vary most of the time. Say there are many child
> processes who are going to write different strings of different sizes
> into the shared memory, how do I decide how much big size of shared
> memory I may be required.
> Its possible that child processes would keep writing into the buffer
> and parent process may also read them simoultaneously and remove it
> from the shared memory, but during corner cases , its likely that child
> processes (producer) writes into the shared memory faster than the
> parent process (consumer) can consume it and very soon fills up the
> shared memory. In that case can shared memory be expanded?
> So in nutshell 2 questions:
> 1) How best to determine the maximum size of the file mapping object
> when we have multiple child processes coming and writing into the
> shared memory with varying string sizes.
> 2) Can shared memory be expanded later once it gets full?
> Thanks
You can add shared memory blocks, and with some luck they may be
contiguous, you since you can't count on it, you'll have to manage
disjoint memory blocks. (You can implement a "virtual memory mapping",
going thru a vector of indirect pointers).
Note that when you have several processes, it's complicated to add
shared memory blocks, since all the processes need to do it. It's
better to allocate th needed buffer at the start.
But in any case, you'll have to deal with resource exhaustion.
And when you have several writers, or several reader, you need to
ensure mutual exclusion when they try to write or read at the same
time. That means the use of semaphores (mutexes and conditions work
only for threads inside a process).
man semget
man semop
So in addition to the semaphores used to implement the mutex on the
access of the shared memory, you'll have to use a semaphore to handle
the flow control between writers and readers. That means that when
the buffer is full, the writters will block on the semaphore, until
the readers free enough space.
If the messages can be of varying size, it's best to manage it as
such, it's not much more complicated to handle variable size data than
fixed size.
--
__Pascal Bourguignon__ http://www.informatimago.com/
NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
|
|
|
|
|