tags:

views:

133

answers:

2

This code should take an integer, create pipes, spawn two children, wait until they are dead, and start all over again. However, around the third time around the loop I lose my prompt to enter a number and it no longer prints the number I've entered. Any ideas?

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

#define WRITE   1
#define READ    0

int main (int argc, const char * argv[]) {

    //Pipe file-descriptor array
    unsigned int isChildA = 0;
    int pipeA[2];
    int pipeB[2];
    int num = 0;

    while(1){


    fprintf(stderr,"Enter an integer: ");
    scanf("%i", &num);

    if(num == 0){
        fprintf(stderr,"You entered zero, exiting...\n");
        exit(0);
    }

    //Open Pipes
    if(pipe(pipeA) < 0){
        fprintf(stderr,"Could not create pipe A.\n");
        exit(1);
    }

    if(pipe(pipeB) < 0){
        fprintf(stderr,"Could not create pipe B.\n");
        exit(1);
    }

    fprintf(stderr,"Value read: %i \n", num);
    fprintf(stderr,"Parent PID: %i\n", getpid());

    pid_t procID = fork();

    switch (procID) {
        case -1:
            fprintf(stderr,"Fork error, quitting...\n");
            exit(1);
            break;

        case 0:
            isChildA = 1;
            break;

        default:
            procID = fork();

            if (procID<0) {
                fprintf(stderr,"Fork error, quitting...\n");
                exit(1);
            }
            else if(procID == 0){
                isChildA = 0;
            }

            else {

                write(pipeA[WRITE], &num, sizeof(int));
                close(pipeA[WRITE]);
                close(pipeA[READ]);
                close(pipeB[WRITE]);
                close(pipeB[READ]);

                pid_t pid;

                while (pid = waitpid(-1, NULL, 0)) {
                    if (errno == ECHILD) {
                        break;
                    }
                }

            }


            break;
    }

    if (procID == 0) {
        //We're a child, do kid-stuff.
        ssize_t bytesRead = 0;
        int response;

        while (1) {

            while (bytesRead == 0) {
                bytesRead = read((isChildA?pipeA[READ]:pipeB[READ]), &response, sizeof(int));
            }
            if (response < 2) {
                //Kill other child and self
                fprintf(stderr, "Terminating PROCID: %i\n", getpid());
                write((isChildA?pipeB[WRITE]:pipeA[WRITE]), &response, sizeof(int));
                close(pipeA[WRITE]);
                close(pipeA[READ]);
                close(pipeB[WRITE]);
                close(pipeB[READ]);
                return 0;
            }
            else if(!(response%2)){
                //Even
                response/=2;
                fprintf(stderr,"PROCID: %i, VALUE: %i\n", getpid(), response);
                write((isChildA?pipeB[WRITE]:pipeA[WRITE]), &response, sizeof(int));
                bytesRead = 0;
            }

            else {
                //Odd
                response*=3;
                response++;
                fprintf(stderr,"PROCID: %i, VALUE: %i\n", getpid(), response);
                write((isChildA?pipeB[WRITE]:pipeA[WRITE]), &response, sizeof(int));
                bytesRead = 0;
            }


        }
    }
}

    return 0;
}

This is the output I am getting...

bash-3.00$ ./proj2 
Enter an integer: 101
Value read: 101 
Parent PID: 9379
PROCID: 9380, VALUE: 304
PROCID: 9381, VALUE: 152
PROCID: 9380, VALUE: 76
PROCID: 9381, VALUE: 38
PROCID: 9380, VALUE: 19
PROCID: 9381, VALUE: 58
PROCID: 9380, VALUE: 29
PROCID: 9381, VALUE: 88
PROCID: 9380, VALUE: 44
PROCID: 9381, VALUE: 22
PROCID: 9380, VALUE: 11
PROCID: 9381, VALUE: 34
PROCID: 9380, VALUE: 17
PROCID: 9381, VALUE: 52
PROCID: 9380, VALUE: 26
PROCID: 9381, VALUE: 13
PROCID: 9380, VALUE: 40
PROCID: 9381, VALUE: 20
PROCID: 9380, VALUE: 10
PROCID: 9381, VALUE: 5
PROCID: 9380, VALUE: 16
PROCID: 9381, VALUE: 8
PROCID: 9380, VALUE: 4
PROCID: 9381, VALUE: 2
PROCID: 9380, VALUE: 1
Terminating PROCID: 9381
Terminating PROCID: 9380
Enter an integer: 102
Value read: 102 
Parent PID: 9379
PROCID: 9386, VALUE: 51
PROCID: 9387, VALUE: 154
PROCID: 9386, VALUE: 77
PROCID: 9387, VALUE: 232
PROCID: 9386, VALUE: 116
PROCID: 9387, VALUE: 58
PROCID: 9386, VALUE: 29
PROCID: 9387, VALUE: 88
PROCID: 9386, VALUE: 44
PROCID: 9387, VALUE: 22
PROCID: 9386, VALUE: 11
PROCID: 9387, VALUE: 34
PROCID: 9386, VALUE: 17
PROCID: 9387, VALUE: 52
PROCID: 9386, VALUE: 26
PROCID: 9387, VALUE: 13
PROCID: 9386, VALUE: 40
PROCID: 9387, VALUE: 20
PROCID: 9386, VALUE: 10
PROCID: 9387, VALUE: 5
PROCID: 9386, VALUE: 16
PROCID: 9387, VALUE: 8
PROCID: 9386, VALUE: 4
PROCID: 9387, VALUE: 2
PROCID: 9386, VALUE: 1
Terminating PROCID: 9387
Terminating PROCID: 9386
Enter an integer: 104
Value read: 104 
Parent PID: 9379
Enter an integer: PROCID: 9388, VALUE: 52
PROCID: 9389, VALUE: 26
PROCID: 9388, VALUE: 13
PROCID: 9389, VALUE: 40
PROCID: 9388, VALUE: 20
PROCID: 9389, VALUE: 10
PROCID: 9388, VALUE: 5
PROCID: 9389, VALUE: 16
PROCID: 9388, VALUE: 8
PROCID: 9389, VALUE: 4
PROCID: 9388, VALUE: 2
PROCID: 9389, VALUE: 1
Terminating PROCID: 9388
Terminating PROCID: 9389
105
Value read: 105 
Parent PID: 9379
Enter an integer: PROCID: 9395, VALUE: 316
PROCID: 9396, VALUE: 158
PROCID: 9395, VALUE: 79
PROCID: 9396, VALUE: 238
PROCID: 9395, VALUE: 119
PROCID: 9396, VALUE: 358
PROCID: 9395, VALUE: 179
PROCID: 9396, VALUE: 538
PROCID: 9395, VALUE: 269
PROCID: 9396, VALUE: 808
PROCID: 9395, VALUE: 404
PROCID: 9396, VALUE: 202
PROCID: 9395, VALUE: 101
PROCID: 9396, VALUE: 304
PROCID: 9395, VALUE: 152
PROCID: 9396, VALUE: 76
PROCID: 9395, VALUE: 38
PROCID: 9396, VALUE: 19
PROCID: 9395, VALUE: 58
PROCID: 9396, VALUE: 29
PROCID: 9395, VALUE: 88
PROCID: 9396, VALUE: 44
PROCID: 9395, VALUE: 22
PROCID: 9396, VALUE: 11
PROCID: 9395, VALUE: 34
PROCID: 9396, VALUE: 17
PROCID: 9395, VALUE: 52
PROCID: 9396, VALUE: 26
PROCID: 9395, VALUE: 13
PROCID: 9396, VALUE: 40
PROCID: 9395, VALUE: 20
PROCID: 9396, VALUE: 10
PROCID: 9395, VALUE: 5
PROCID: 9396, VALUE: 16
PROCID: 9395, VALUE: 8
PROCID: 9396, VALUE: 4
PROCID: 9395, VALUE: 2
PROCID: 9396, VALUE: 1
Terminating PROCID: 9395
Terminating PROCID: 9396
105
Value read: 105 
Parent PID: 9379
Enter an integer: PROCID: 9397, VALUE: 316
PROCID: 9398, VALUE: 158
PROCID: 9397, VALUE: 79
PROCID: 9398, VALUE: 238
PROCID: 9397, VALUE: 119
PROCID: 9398, VALUE: 358
PROCID: 9397, VALUE: 179
PROCID: 9398, VALUE: 538
PROCID: 9397, VALUE: 269
PROCID: 9398, VALUE: 808
PROCID: 9397, VALUE: 404
PROCID: 9398, VALUE: 202
PROCID: 9397, VALUE: 101
PROCID: 9398, VALUE: 304
PROCID: 9397, VALUE: 152
PROCID: 9398, VALUE: 76
PROCID: 9397, VALUE: 38
PROCID: 9398, VALUE: 19
PROCID: 9397, VALUE: 58
PROCID: 9398, VALUE: 29
PROCID: 9397, VALUE: 88
PROCID: 9398, VALUE: 44
PROCID: 9397, VALUE: 22
PROCID: 9398, VALUE: 11
PROCID: 9397, VALUE: 34
PROCID: 9398, VALUE: 17
PROCID: 9397, VALUE: 52
PROCID: 9398, VALUE: 26
PROCID: 9397, VALUE: 13
PROCID: 9398, VALUE: 40
PROCID: 9397, VALUE: 20
PROCID: 9398, VALUE: 10
PROCID: 9397, VALUE: 5
PROCID: 9398, VALUE: 16
PROCID: 9397, VALUE: 8
PROCID: 9398, VALUE: 4
PROCID: 9397, VALUE: 2
PROCID: 9398, VALUE: 1
Terminating PROCID: 9397
Terminating PROCID: 9398
106
Value read: 106 
Parent PID: 9379
Enter an integer: PROCID: 9399, VALUE: 53
PROCID: 9400, VALUE: 160
PROCID: 9399, VALUE: 80
PROCID: 9400, VALUE: 40
PROCID: 9399, VALUE: 20
PROCID: 9400, VALUE: 10
PROCID: 9399, VALUE: 5
PROCID: 9400, VALUE: 16
PROCID: 9399, VALUE: 8
PROCID: 9400, VALUE: 4
PROCID: 9399, VALUE: 2
PROCID: 9400, VALUE: 1
Terminating PROCID: 9399
Terminating PROCID: 9400
^C

Another thing that's strange, when ran from within XCode it behaves normally. However, when ran from bash on Solaris or OSX it acts up.

A: 

Call fflush after fprintf, when there is no newline at the end of the printed string.

Tuomas Pelkonen
Thanks for the answer, but I've tried that. It was my understanding that stderr isn't buffered like stdout so fflush wouldn't be needed.
Steve Melvin
That is correct, stderr is not buffered.
tomlogic
+3  A: 

Replace your waitpid() and try this instead:

/*
while (pid = waitpid( -1, NULL, 0))
{
    if (errno == ECHILD)
    {
        break;
    }
}
*/

while (1)
{
    if ((pid = waitpid(-1, NULL, 0)) == -1)
    {
        if (errno == ECHILD)
            break;
    }
    else
        printf("I am %d and I am reaped  %d\n", getpid(), pid);
}
Duck
Thanks! That worked! But could you explain a little of what your solution does different than what I had?
Steve Melvin
waitpid() doesn't reset errno on success so after the 1st ECHILD the error code was left in place. On the next iteration, even though waitpid() found a child the loop was exiting on the ECHILD test and not catching the 2nd child. That messed up the print sequence.
Duck