Solved

help on a ring problem.

Posted on 1998-05-02
7
371 Views
Last Modified: 2013-12-26
Hi I am studying unix programming. However, I have difficulties to do one problem on a book(practical unix programming). There is no solutions provided in the book! I need to modify the following program to make it a bidirectinal ring so that the inormation can flow in either direction between neighbors on the ring.  

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/*
 * Sample C program for generating a unidirectional ring of processes.
 * Invoke this program with a command-line argument indicating the
 * number of processes on the ring.  Communication is done via pipes
 * that connect the standard output of a process to the standard input
 * of its successor on the ring.  After the ring is created, each
 * process identifies itself with its process ID and the process ID
 * of its parent.  Each process then exits.
 */
 
void main(int argc,  char *argv[ ])
{
   int   i;             /* number of this process (starting with 1)   */
   int   childpid;      /* indicates process should spawn another     */
   int   nprocs;        /* total number of processes in ring          */
   int   fd[2];         /* file descriptors returned by pipe          */
   int   error;         /* return value from dup2 call                */
   int       status;
    /* check command line for a valid number of processes to generate */
   if ( (argc != 2) || ((nprocs = atoi (argv[1])) <= 0) ) {
       fprintf (stderr, "Usage: %s nprocs\n", argv[0]);
       exit(1);
   }
                        /* connect std input to std output via a pipe */
   if (pipe (fd) == -1) {
      perror("Could not create pipe");
      exit(1);
   }
   if ((dup2(fd[0], STDIN_FILENO) == -1) ||
       (dup2(fd[1], STDOUT_FILENO) == -1)) {
      perror("Could not dup pipes");
      exit(1);
   }
   if ((close(fd[0]) == -1) || (close(fd[1]) == -1)) {
      perror("Could not close extra descriptors");
      exit(1);
   }
        /* create the remaining processes with their connecting pipes */
   for (i = 1; i < nprocs;  i++) {
      if (pipe (fd) == -1) {
         fprintf(stderr,"Could not create pipe %d: %s\n",
            i, strerror(errno));
         exit(1);
      }  
      if ((childpid = fork()) == -1) {
         fprintf(stderr, "Could not create child %d: %s\n",
            i, strerror(errno));
         exit(1);
      }  
      if (childpid > 0)        /* for parent process, reassign stdout */
          error = dup2(fd[1], STDOUT_FILENO);
      else
          error = dup2(fd[0], STDIN_FILENO);
      if (error == -1) {
         fprintf(stderr, "Could not dup pipes for iteration %d: %s\n",
                 i, strerror(errno));
         exit(1);
      }  
      if ((close(fd[0]) == -1) || (close(fd[1]) == -1)) {
         fprintf(stderr, "Could not close extra descriptors %d: %s\n",
                i, strerror(errno));
         exit(1);
      }
      if (childpid)
         break;
   }

   wait(&status);
                                  /* say hello to the world */
   fprintf(stderr,"This is process %d with ID %d and parent id %d\n",
      i, (int)getpid(), (int)getppid());
   exit (0);
}     /* end of main program here */

0
Comment
Question by:pete_host
  • 4
  • 2
7 Comments
 
LVL 1

Accepted Solution

by:
mrausch earned 250 total points
ID: 1292667
If you are running this on a SVR4, you automatically have a
bidirectional ring as far as you don't use the stdio routines
to access the pipe. That is, if you access the file descriptors
directly with write() and read(), it is perfectly valid for your
ring to write to fd 0 ("stdin") and read from fd 1 ("stdout").

If you want to use the stdio routines, you could add something
like this (not tested though)

[...]
      int   error;         /* return value from dup2 call                */
      int   status;
+      FILE *STDINREV, *STDOUTREV; /* FILE descriptors to write to the previous
+                                     or read from the next process in the ring */
[...]
      if (childpid)
             break;
       }
    }
+
+    /* now create new FILE descriptors for the reverse direction in the ring */
+    if ( (STDOUTREV = fdopen(STDIN_FILENO, "w")) == NULL ||
+         (STDINREV = fdopen(STDOUT_FILENO, "r")) == NULL ) {
+            perror("Could not open descriptor for reverse direction");
+            exit(1);
+    }
+
   wait(&status);
[...]

to your code and use e.g. fprintf(STDOUTREV,"whatever\n") to
write to the previous process.
This is not portable though, for example Linux doesn't know this
new semantic of pipe().

To implement it in a portable way, you just have to open up a
second pipe for the reverse direction, and in case you want to
use STDIO on this as well, use the fdopen() method to get FILE*
descriptors for these pipes as well. One thing is different though, you might run into problems if you want fixed fd's for
the reverse direction (say, fd 3 and 4). To be on the safe side,
you should access the new pipes via variables containing the fd.

Do you need code for this or do you want to try yourself?

0
 

Author Comment

by:pete_host
ID: 1292668
Hi mrausch,
thank you for your help on this problem. Actually, i still have a little bit confused about this problem. Can you show me the code for this problem? I am running linux for this problem.


0
 
LVL 2

Expert Comment

by:seedy
ID: 1292669
Home assignment?!  pete_host, why don't you post what you have coded so far?
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:pete_host
ID: 1292670
here is the code i have, but i don't know why it is not working right?

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>


void main(int argc, char *argv[])
{
      
      int  i;
      int childpid;
      int nprocs;
      int fd[2];
      int error;
      int p1[2];
      int p2[2];
      int p3[2];
      int p4[2];
      int start=1;


      if ((argc !=2)|| ((nprocs = atoi(argv[1]))<=0)) {
      fprintf (stderr, "Usage: %s processes\n", argv[0]);
      exit (1);

      }
      if (pipe (p1) == -1) {
          perror("Could not create pipe1");
          exit(1);
      }
      if (pipe (p2) == -1) {
          perror("Could not create pipe2");
          exit(1);
      }
      if (pipe (p3) == -1) {
          perror("Could not create pipe3");
          exit(1);
      }
      if (pipe (p4) == -1) {
          perror("Could not create pipe4");
          exit(1);
      }
      if ((childpid= fork()) == -1) {
            fprintf(stderr, "Could not create child %d: %s \n",
            i, strerror(errno));
            exit(1);
            }
      if (childpid){
            if ((dup2(p2[0], p1[1]) == -1) ||
                (dup2(p3[0], p2[0]) == -1)||
                (dup2(p4[1], p2[1]) == -1)){
                  perror("Could not dup pipes");
                  exit(1); }

            if ((close(p3[0]) == -1) || (close(p3[1]) == -1) ||
                      (close(p4[0]) == -1) || (close(p4[1]) == -1)){
                   perror("Could not close extra descriptors");
                  exit(1);}
                }
      else{
            if ((dup2(p1[1], p1[0]) == -1) ||
                (dup2(p2[0], p1[1]) == -1)||
                (dup2(p3[1], p2[0]) == -1)||
                (dup2(p4[0], p2[1]) == -1)){
                  perror("Could not dup pipes");
                  exit(1); }
            if ((close(p3[0]) == -1) || (close(p3[1]) == -1) ||
                      (close(p4[0]) == -1) || (close(p4[1]) == -1)){
                   perror("Could not close extra descriptors");
                  exit(1);}
          }

      for (i=1; i<nprocs; i++) {
            if (i==1) { break;};

      if (childpid){
            if ((dup2(p2[0], p1[0]) == -1) ||
                (dup2(p2[1], p1[1]) == -1)||
                (dup2(p3[0], p2[0]) == -1)||
                (dup2(p4[1], p2[1]) == -1)){
                  perror("Could not dup pipes");
                  exit(1); }
            if ((close(p3[0]) == -1) || (close(p3[1]) == -1) ||
                      (close(p4[0]) == -1) || (close(p4[1]) == -1)){
                   perror("Could not close extra descriptors");
                  exit(1);}
            break;}
      else {
            if ((dup2(p3[1], p2[0]) == -1) ||
                (dup2(p4[0], p2[1]) == -1)){
                  perror("Could not dup pipes");
                  exit(1); }
            if ((close(p3[0]) == -1) || (close(p3[1]) == -1) ||
                      (close(p4[0]) == -1) || (close(p4[1]) == -1)){
                   perror("Could not close extra descriptors");
                  exit(1);}
            
            if (pipe(p3) == -1) {
            fprintf(stderr, "Could not create child %d: %s \n",
            i, strerror(errno));
            exit(1);
            }
            if (pipe(p4) == -1) {
            fprintf(stderr, "Could not create child %d: %s \n",
            i, strerror(errno));
            exit(1);
            }
            if ((childpid= fork()) == -1) {
            fprintf(stderr, "Could not create child %d: %s \n",
            i, strerror(errno));
            exit(1);
            }
      }
   }
   fprintf(stderr, "process #i:%d process ID: %ld parent ID: %ld \n",
    i, (int) getpid(), (int) getppid());
      exit(0);
}

0
 

Author Comment

by:pete_host
ID: 1292671
Adjusted points to 250
0
 

Author Comment

by:pete_host
ID: 1292672
anybody help me on this? I need to hand in the hw tomorrow!
0
 
LVL 2

Expert Comment

by:seedy
ID: 1292673
Please see the question "Token Ring(Bidirectional)" under C Language topic area, at:
http://www.experts-exchange.com/topics/comp/lang/c/Q.10050266

0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now