// Author: Prof. Chee Yap // Modified by Chien-I Liao // Mar 2005 /* * gcd_par.c * * MULTI-PROCESS GCD COMPUTATION * * When you call "gcd_par" with n pairs of integers, * the parent process will spawn n child processes. Each child process * will compute the gcd of a pair of integers. * * The Euclidean algorithm is used: the GCD * of m, n (where m>n>=0) is computed via a sequence * * m_0 > m_1 > m_2 >...> m_k > m_{k+1} = 0 * * where m_{i+1} = m_{i-1} mod m_i for all i. * We return m_k as the GCD of m,n. * * However, each child process must call the parent process * to compute the mod operation. We set up two pipes * pipe2parent[] and pipe2child[] * between each child and the parent. The child will write * a pair of numbers (a,b) onto one pipe, and signal the parent. * Upon receiving the signal, the parent will search through * the pipes, trying to read (a,b) from one of the pipes. This * reading must be done in a NON-BLOCKING WAY. When (a,b) is * found, the parent will write (a mod b) to the other pipe for the * same child. The child will keep doing this until it receives * a 0 from one of these calls. Then it prints the GCD and exits. * * The parent waits for n exits from its children and then it exits. * * E.g., * > gcd_par 100 154 3 2 25 15 * * gcd=4 * * gcd=1 * * gcd=5 * * parent exits! * * BUG: We need to call "sleep(1)" to slow down * down the processes, or else program hangs * when there are more than 2 processes * * Author: Chee Yap (Feb 2005) **/ #include #include #include #include #include #include #include #include //////////////////////////////////////////////////// // buffers char buf[1024]; //////////////////////////////////////////////////// // Pipes const int MaxNoPairs=20; int pipe2parent[20][2]; int pipe2child[20][2]; //////////////////////////////////////////////////// // Set status flag for files void set_fl(int fd, int flags) // flag=file status flags to turn on { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0) perror("fcntl F_GETFL error"); val |= flags; // turn on flags if (fcntl(fd, F_SETFL, val)<0) perror("fcntl F_SETFL error"); } //////////////////////////////////////////////////// // Clear buffer clearbuf(char *buff){ int i; for (i=0; i<1024; i++) buf[i]='\0'; } //////////////////////////////////////////////////// // main main(int argc, char ** argv) { int kk; int NumPairs = (argc-1)/2; printf("Number of Pairs = %d\n", NumPairs); if (NumPairs> MaxNoPairs) perror("too many pairs"); int i; int m, n, p, mm; int len; int child_pid, parent_pid; /////////////////////////////////////////// // signal int signal_count=0; // safety feature void int_handler(int sig) { signal(sig, int_handler); // reset handler! if (signal_count>80) exit(0); // safety feature int i, m, n, len; for (i=0; i0) { sscanf(buf,"%d %d ", &m, &n); sprintf(buf,"%d\0", m%n); printf("Signal counter=%d, Return value=%d\n", signal_count++, m%n); len=strlen(buf); if (len != write(pipe2child[i][1],buf,len)) perror("write in signal"); return; } } } signal(SIGUSR1, int_handler); parent_pid = getpid(); //main loop //////////////////////////////////////////////////// for (i=0; i< NumPairs; i++){ // get args m = atoi(argv[2*i + 1]); n = atoi(argv[2*i + 2]); if (m0) { sleep(1);// WHY IS THIS NEEDED? // write m and n clearbuf(buf); sprintf(buf,"%d %d ",m,n); len = strlen(buf); if (len != write(pipe2parent[i][1],buf,len)) perror("write to parent"); kill(parent_pid, SIGUSR1); // read p clearbuf(buf); read(pipe2child[i][0], buf, 1024); sscanf(buf,"%d", &p); m=n; n=p; } printf("gcd= %d\n", m); exit(0); break; default: // parent close(pipe2parent[i][1]); close(pipe2child[i][0]); }//switch }//for i for (i=0; i< NumPairs; i++){ wait(&child_pid); printf("caught one child: %d\n", child_pid); } }//main ////////////////////////////////////////////////////