1

Following question:

I created a shared memory segment (in my main.c), containing multiple structures, a few variables etc. Right after that, I am -creating a pipe, and -fork()-ing.

I am making both the child, and parent process communicate through the pipe - whose socket descriptors are both stored in a global structure, saved in the shared memory segment. Now I read that for elements contained in a shared memory segment, after forking, both processes can manipulate the shared variables and structures, and that the other process sharing the memory would thereby have access to the same, manipulated data. So far, so good!

My question is not a a source code issue, it is rather more a theoretical point I seem to be missing, since my code is working exactly the way it should, but I don't understand why this works:

After forking, I make each process close it's irrelevant (for my purposes), side of the pipe (e.g. the parent closes the reading side of the pipe, the child the writing side). However, the pipe_fd[2] is stored in the global struct in the SHM segment. So how come, if one side is closed from one process, and the other side from the other process (accessing respectively by using

 close(nameOfSHMStruct->pipe_fd[0]);

and

 close(nameOfSHMStruct->pipe_fd[1]);

), but both access it form the struct, that they are still able to communicate with each-other? am I missing a something about the pipe()-statement , or is it something with the SHM, or is it something with the fork(), or god knows something about the combination of all the 3 of them? As I said already, the code actually works this way, I'm printing (as a debug message), the data exchanged between the processes, but I just don't really get the core theoretical aspect behind it's way of functioning...

Spade Johnsson
  • 522
  • 2
  • 7
  • 23

2 Answers2

2

They are able to communicate beacause they only close their descriptors of the pipe. I will explain deeply:

FATHER PROCCESS          ----->  FORK() ------>>> FATHER PROCESS

pipe() -> pipe_fd[2]                     |         pipe_fd[2] (father pipe fds)
                                         |
                                         ----->>> CHILD PROCESS
                                                  pipe_fd[2] (child pipe fds)

A fork clones the father process, including the file descriptors: the child owns a copy of the file descriptors of its father. So after a fork, we will have 2 file descriptors for each process.

So, considering this, you should not store the pipe file descriptors in a shared memory structure, beacause it is pointing to conceptually different fd's in the father and in the children.

Here and here more info.

Community
  • 1
  • 1
1

It would helpful to see more of the code, but I'll take a guess.

The 'pipe_fd' created with the call to pipe() is copied to the child process upon fork(). Since the memory space is also copied on fork, that pointer in your shm object distinctly points to the memory address in the parent or child. So calling close, even though on the 'pipe_fd' in the shm, is actually pointing to the 'pipe_fd' in the parent or child respectively.

I guess an easier of looking at it is: all you've placed in that shm object is a pointer, which is shared across the processes, and since the address space is copied (which includes that pipe_fd), the pointer points to the same address in the parent or child, which is their own copy of that 'pipe_fd'.

djp
  • 183
  • 1
  • 6
  • Unless the whole memory is copied in a fork, the space address in each process is absolutely different, so it will fail. In nameOfSHMStruct->pipe_fd he's accessing the content of the shared memory, wich is at least an offset of the file descriptor table of the process. – Jon Ander Ortiz Durántez Jan 26 '14 at 19:50
  • That is precisely what fork does. See http://linux.die.net/man/2/fork "The child process is created with a single thread--the one that called fork(). The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects;". The descriptor for nameOfSHMStruct gets duplicated, which lets him access it in the child, but pipe_fd is still just a pointer, which will point to the address of the parent/child respectively. – djp Jan 26 '14 at 20:15
  • I should clarify, I am saying in general don't use pointers in shared memory. However, in this specific case, all that 'pipe_fd' points to is an array of two integers (likely 5 and 6). Since the descriptors are copied (you'd see 1-6 in both parent and child), calling close(shm->pipe_fd[0]) is really just calling close(5). Which doesn't affect the other processes descriptor number 5. – djp Jan 26 '14 at 21:34
  • O_o Try to share pointers across processes using shared memory, and see [what](http://stackoverflow.com/questions/10776762/pointers-inside-shared-memory-segment) happens. And I will say it again: a file descriptor is not a pointer, it's an int number wich is the offset of the file descriptor in the table of the process. Check it [here](http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.genprogc/doc/genprogc/fdescript.htm): _File descriptors are indexes to the file descriptor table in the u_block area maintained by the kernel for each process._ – Jon Ander Ortiz Durántez Jan 26 '14 at 21:39
  • Just wrote the last comment without reading your clariffy. There you point the correct keys. – Jon Ander Ortiz Durántez Jan 26 '14 at 21:41