Home > Archive > Unix Programming > November 2005 > Three processes intercommunicating(both ways) using pipes, (six pipes??)
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 |
Three processes intercommunicating(both ways) using pipes, (six pipes??)
|
|
| mirtoni 2005-11-27, 7:56 am |
| Hi, I'm new here, so Hello to all...
I'm posting because I have searched this news group and others but
found nothing on hot to solve this...
Ok, the concept is easy...
Three processes. Each one should be able to comunicate with each other
(both ways) using pipes. So I think that I need six pipes (two pipes
between each process).
Now if the above is true then tell me how can I do it...
Below is the code of the root process that spawns the three processes
using fork() and execl()...
Here I am just trying to make the server (child) to be the middle
process comunicating both ways between the client(parent) and the
process3(grandchild). If i figure this our than I will have to add also
communication between client and process3 to from a kind of a loop.
#define WRITE 1
#define READ 0
int to_child[2], to_parent[2], child_to_proc3[2], proc3_to_child[2];
int main()
{
int f,koniec,dlugosc;
if (pipe(to_child) < 0) {
write(STDERR_FILENO,KOM_PIPE1,strlen(KOM
_PIPE1));
return 1; }
if (pipe(to_parent) < 0) {
write(STDERR_FILENO,KOM_PIPE2,strlen(KOM
_PIPE2));
return 1; }
if (pipe(child_to_proc3) < 0) {
write(STDERR_FILENO,KOM_PIPE2,strlen(KOM
_PIPE2));
return 1; }
if (pipe(proc3_to_child) < 0) {
write(STDERR_FILENO,KOM_PIPE2,strlen(KOM
_PIPE2));
return 1; }
if ((f=fork()) == -1)
{
write(STDERR_FILENO,FORK,strlen(FORK));
return(1); }
else
if (f == 0)
{ //PROCESS 3
if(fork==0){
close(READ);
if ((dup(child_to_proc3[READ])) < 0) {
write(STDERR_FILENO,"error duplikating READ proc3",strlen("error
duplikating READ proc3"));
return(1);
}
close(WRITE);
if ((dup(proc3_to_child[WRITE])) < 0) {
write(STDERR_FILENO,"error duplikating WRITE proc3",strlen("error
duplikating WRITE proc3"));
return(1);
}
close(child_to_proc3[WRITE]);
close(proc3_to_child[READ]);
close(child_to_proc3[READ]);
close(proc3_to_child[WRITE]);
execl("proc3",NULL);
}
/*SERVER/
close(READ);
if ((dup(to_child[READ])) < 0) {
write(STDERR_FILENO,KOM_DUP1,strlen(KOM_
DUP1));
return(1); }
close(WRITE);
if ((dup(to_parent[WRITE])) < 0) {
write(STDERR_FILENO,KOM_DUP2,strlen(KOM_
DUP2));
return(1); }
close(WRITE);
if ((dup(child_to_proc3[WRITE])) < 0) {
write(STDERR_FILENO,"error duplikating WRITE potom",strlen("error
duplikating WRITE potom"));
return(1);
}
close(READ);
if ((dup(proc3_to_child[READ])) < 0) {
write(STDERR_FILENO,"error duplikating READ potom",strlen("error
duplikating READ potom"));
return(1);
}
close(child_to_proc3[WRITE]);
close(proc3_to_child[READ]);
close(child_to_proc3[READ]);
close(proc3_to_child[WRITE]);
close(to_parent[WRITE]);
close(to_child[READ]);
close(to_parent[READ]);
close(to_child[WRITE]);
execl("server",NULL);
write(STDERR_FILENO,EXEC_SW,strlen(EXEC_
SW));
return(1);
}
else
{ /CLIENT
*/
close(WRITE);
if ((dup(to_child[WRITE])) < 0) {
write(STDERR_FILENO,KOM_DUP3,strlen(KOM_
DUP3));
return(1); }
close(READ);
if ((dup(to_parent[READ])) < 0) {
write(STDERR_FILENO,KOM_DUP4,strlen(KOM_
DUP4));
return(1); }
close(to_child[WRITE]);
close(to_parent[READ]);
close(to_child[READ]);
close(to_parent[WRITE]);
execl("client",NULL);
write(STDERR_FILENO,EXEC_KL,strlen(EXEC_
KL));
return(1);
}
}
I know that I'm missing the entire point of pipes, but I just dont
understatnd how all of this works, cause I'm new to unix OS and not
very good at C lang.
Any help would be appreciated...
Thank you.
| |
| Pascal Bourguignon 2005-11-27, 7:00 pm |
| "mirtoni" <mirton@gmail.com> writes:
> Hi, I'm new here, so Hello to all...
>
> I'm posting because I have searched this news group and others but
> found nothing on hot to solve this...
>
> Ok, the concept is easy...
> Three processes. Each one should be able to comunicate with each other
> (both ways) using pipes. So I think that I need six pipes (two pipes
> between each process).
>
> Now if the above is true then tell me how can I do it...
This is easy if you abstract a little.
;; Ignore this first section, we're just simulating the POSIX primitives used:
(defparameter *fd* 3)
(defun pipe () (let ((res (list (incf *fd*) (incf *fd*))))
(print `(creating pipes ,res))
res))
(defun pipe-in (p) (elt p 0))
(defun pipe-out (p) (elt p 1))
(defun close-fd (fd) (print `(closed ,fd)))
(defun dup2 (src dst) (print `(dupped ,src to ,dst)))
(defparameter *next-pid* 1000)
(defparameter *pid* (incf *next-pid*))
(defun fork (parent child)
(print '(fork))
(let ((*pid* *pid*))
(print `(in parent pid = ,*pid*))
(funcall parent))
(let ((*pid* (incf *next-pid*)))
(print `(in child pid = ,*pid*))
(funcall child)))
(defun reset () (setf *fd* 3 *next-pid* 1000 *pid* (incf *next-pid*)))
;; Our abstraction: we buid a ring of pipes.
(defun make-ring (n)
"Returns a list of n 4-uples of file descriptors:
(left-in left-out right-in right-out)"
;; you could write an interative version too, instead of this recursive one:
(cond
((= 0 n) '())
((= 1 n) (let ((f0 (pipe))
(f1 (pipe)))
(list (list (pipe-in f0)
(pipe-out f1)
(pipe-in f1)
(pipe-out f0)))))
(t
;; a 1-->b-->c-->3 a a 1-->b-->c-->3 d 5-->7 a
;; 2<-- <-- <--4 2<-- <-- <--4 6<--8
(let* ((ring (make-ring (1- n)))
(a (car (last ring)))
(f0 (pipe))
(f1 (pipe)))
(prog1 (cons (list (pipe-in f0) ; 5
(pipe-out f1) ; 6
(elt a 2) ; 3
(elt a 3)) ; 4
ring)
(setf (elt a 2) (pipe-in f1) ; 7
(elt a 3) (pipe-out f0))))))) ; 8
(defun close-others (ring index)
"Close all the file descriptors in the ring, but those in the 4-uple at index."
(loop
:for i :from 0
:for s :in ring
:unless (= i index)
:do (map nil (function close-fd) s)))
(defun fork-functions (funs)
"Builds a ring of pipes,
forks worker children processes connected with the pipes,
each of which calls one of the functions in funs."
(loop
:with ring = (make-ring (length funs))
:for fun :in funs
:for pipes :in ring
:for index :from 0
:do (fork (lambda () (print '(go on forking worker processes)))
(lambda ()
(close-fd 0)
(close-fd 1)
(close-fd 2)
(close-others ring index)
(dotimes (i 4) (dup2 (elt pipes i) i))
(funcall fun)))
:finally
(print `(in parent pid = ,*pid*))
(print '(exit))))
That's it, three little understandable functions that can be used as simply as:
(fork-functions
(list (lambda () (print '(execl worker child one)))
(lambda () (print '(execl worker child two)))
(lambda () (print '(execl worker child three)))))
(CREATING PIPES (4 5))
(CREATING PIPES (6 7))
(CREATING PIPES (8 9))
(CREATING PIPES (10 11))
(CREATING PIPES (12 13))
(CREATING PIPES (14 15))
(FORK)
(IN PARENT PID = 1001)
(GO ON FORKING WORKER PROCESSES)
(IN CHILD PID = 1002)
(CLOSED 0)
(CLOSED 1)
(CLOSED 2)
(CLOSED 8)
(CLOSED 11)
(CLOSED 6)
(CLOSED 5)
(CLOSED 4)
(CLOSED 7)
(CLOSED 14)
(CLOSED 13)
(DUPPED 12 TO 0)
(DUPPED 15 TO 1)
(DUPPED 10 TO 2)
(DUPPED 9 TO 3)
(EXECL WORKER CHILD ONE)
(FORK)
(IN PARENT PID = 1001)
(GO ON FORKING WORKER PROCESSES)
(IN CHILD PID = 1003)
(CLOSED 0)
(CLOSED 1)
(CLOSED 2)
(CLOSED 12)
(CLOSED 15)
(CLOSED 10)
(CLOSED 9)
(CLOSED 4)
(CLOSED 7)
(CLOSED 14)
(CLOSED 13)
(DUPPED 8 TO 0)
(DUPPED 11 TO 1)
(DUPPED 6 TO 2)
(DUPPED 5 TO 3)
(EXECL WORKER CHILD TWO)
(FORK)
(IN PARENT PID = 1001)
(GO ON FORKING WORKER PROCESSES)
(IN CHILD PID = 1004)
(CLOSED 0)
(CLOSED 1)
(CLOSED 2)
(CLOSED 12)
(CLOSED 15)
(CLOSED 10)
(CLOSED 9)
(CLOSED 8)
(CLOSED 11)
(CLOSED 6)
(CLOSED 5)
(DUPPED 4 TO 0)
(DUPPED 7 TO 1)
(DUPPED 14 TO 2)
(DUPPED 13 TO 3)
(EXECL WORKER CHILD THREE)
(IN PARENT PID = 1001)
(EXIT)
> Below is the code of the root process that spawns the three processes
> using fork() and execl()...
> Here I am just trying to make the server (child) to be the middle
> process comunicating both ways between the client(parent) and the
> process3(grandchild). If i figure this our than I will have to add also
> communication between client and process3 to from a kind of a loop.
> [...]
> I know that I'm missing the entire point of pipes, but I just dont
> understatnd how all of this works, cause I'm new to unix OS and not
> very good at C lang.
No, the reason why you don't understand how it works, is because it's
too complicated. I don't understand it either. To write
understandable code, you must introduce abstractions and write small
functions.
Also, if you prefer to keep the parent process in the ring:
(defun fork-functions-and-parent (funs)
(labels ((prepare (ring index pipes)
(close-fd 0)
(close-fd 1)
(close-fd 2)
(close-others ring index)
(dotimes (i 4) (dup2 (elt pipes i) i))))
(loop
:with ring = (make-ring (length funs))
:for fun :in funs
:for pipes :in ring
:for index :from 0 :below (1- (length funs))
:do (fork (lambda () (print '(go on forking worker processes)))
(lambda ()
(prepare ring index pipes)
(funcall fun)))
:finally
(print `(in parent pid = ,*pid*))
(prepare ring (1- (length funs)) (car (last ring)))
(funcall (car (last funs))))))
(fork-functions-and-parent
(list (lambda () (print '(execl worker child one)))
(lambda () (print '(execl worker child two)))
(lambda () (print '(execl worker three in parent)))))
(CREATING PIPES (16 17))
(CREATING PIPES (18 19))
(CREATING PIPES (20 21))
(CREATING PIPES (22 23))
(CREATING PIPES (24 25))
(CREATING PIPES (26 27))
(FORK)
(IN PARENT PID = 1001)
(GO ON FORKING WORKER PROCESSES)
(IN CHILD PID = 1004)
(CLOSED 0)
(CLOSED 1)
(CLOSED 2)
(CLOSED 20)
(CLOSED 23)
(CLOSED 18)
(CLOSED 17)
(CLOSED 16)
(CLOSED 19)
(CLOSED 26)
(CLOSED 25)
(DUPPED 24 TO 0)
(DUPPED 27 TO 1)
(DUPPED 22 TO 2)
(DUPPED 21 TO 3)
(EXECL WORKER CHILD ONE)
(FORK)
(IN PARENT PID = 1001)
(GO ON FORKING WORKER PROCESSES)
(IN CHILD PID = 1005)
(CLOSED 0)
(CLOSED 1)
(CLOSED 2)
(CLOSED 24)
(CLOSED 27)
(CLOSED 22)
(CLOSED 21)
(CLOSED 16)
(CLOSED 19)
(CLOSED 26)
(CLOSED 25)
(DUPPED 20 TO 0)
(DUPPED 23 TO 1)
(DUPPED 18 TO 2)
(DUPPED 17 TO 3)
(EXECL WORKER CHILD TWO)
(IN PARENT PID = 1001)
(CLOSED 0)
(CLOSED 1)
(CLOSED 2)
(CLOSED 24)
(CLOSED 27)
(CLOSED 22)
(CLOSED 21)
(CLOSED 20)
(CLOSED 23)
(CLOSED 18)
(CLOSED 17)
(DUPPED 16 TO 0)
(DUPPED 19 TO 1)
(DUPPED 26 TO 2)
(DUPPED 25 TO 3)
(EXECL WORKER THREE IN PARENT)
--
__Pascal Bourguignon__ http://www.informatimago.com/
In deep sleep hear sound,
Cat vomit hairball somewhere.
Will find in morning.
| |
| mirtoni 2005-11-27, 7:00 pm |
| Thanx for the reply, but I'm sorry cause I have no idea what you wrote
above. Is this some kind of pseudo-code. I really appreciate the help,
but I'm not good at low-level programming languages.
While I was waiting for a reply I tried something like this:
Two pipes to which the server process reads and writes to.
And on the other end The Client and Process 3 will read and write to.
This is because the information going through the pipes from one
process will be the same for the other two processes.
So when the server writes, he will have to write it twice with a little
usleep(300) in between. And if one of the other processes writes, then
the server will have to re-route the data to the other process!!!
I still haven't got it going completely, but I hope you can offer me a
better solution with identical information in pipes besides the one I
wrote above..
Thanx.
| |
| Pascal Bourguignon 2005-11-27, 7:00 pm |
| "mirtoni" <mirton@gmail.com> writes:
> Thanx for the reply, but I'm sorry cause I have no idea what you wrote
> above. Is this some kind of pseudo-code.
Yes.
> I really appreciate the help,
> but I'm not good at low-level programming languages.
That's why I wrote higher level pseudo-code.
> While I was waiting for a reply I tried something like this:
>
> Two pipes to which the server process reads and writes to.
> And on the other end The Client and Process 3 will read and write to.
> This is because the information going through the pipes from one
> process will be the same for the other two processes.
> So when the server writes, he will have to write it twice with a little
> usleep(300) in between. And if one of the other processes writes, then
> the server will have to re-route the data to the other process!!!
>
> I still haven't got it going completely, but I hope you can offer me a
> better solution with identical information in pipes besides the one I
> wrote above..
Divide and conquer.
and abstract, abstract, abstract!
That means, don't try to solve several problems at once.
The fact that you consider a process being a server and the others
clients is irrelevant once you've specified you want them to
communicate in a ring of pipes: write a function that just builds this
ring of pipe.
Don't think your server as writting twice. Abstract! Have it write
once, and let the implementation deal with what is needed to have all
recipients receive the data. That means, instead of writting:
write(pipe[WRITE],...);
write:
tell_them(...);
and let the tell_them() function do what needs to be done.
Now, writting twice (or more, what will happen when you'll have 10
processes?!), may not be the most efficient way to multicast data to
processes on the same computer. You could try shared memory (with
semaphores). Then the tell_them() function would copy the data once
to a shared memory block, and increment a semaphore by the count of
recipients. The recipients will then be able to read the data
directly from the shared memory block, and decrement the semaphore.
When the semaphore reaches 0, all recipient processes have read the
data and the shared memory block can be reused for the next message.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Cats meow out of angst
"Thumbs! If only we had thumbs!
We could break so much!"
|
|
|
|
|