0

The output of my program is not consistent when I redirect standard output to a text file. That is ./main and ./main > out.txt have different outputs.

The problem can best be understood by executing the program. Here is my verbal description (in case you would like to read it).

The behavior I get executing with ./main is what I desire. When redirecting the output, the counter I use in my program appears to be reset which is not intended. I have added some extra print statements to help make it more clear.

What I aimed to do: Generate five child processes, and each process write to a buffer (supported by a pipe). Then in main print the buffer of each child process.

This is what happens without redirecting the output. When I redirect the output, I get a recursive/cascaded result. The result for the first process is correct, but each successive process prints the processes that returned before it.

I used valgrind and did not find any memory leaks. I did notice that more than three FD were open which I think might suggest a file descriptor leak.

  • Output 1: goo.gl/Yz534A — without redirection
  • Output 2: goo.gl/zfAWQV — with redirection

SO does not allow the use of URL shorteners

Without redirection

Generated separately; equivalent to, but distinct from, the Google doc image.

Fork Instance:  0

Child Process (30869) Terminating...

Exit Status: Normal Value: 0
0 3 buf:    Message left from: 30869

The value of i is:  0

Fork Instance:  1

Child Process (30870) Terminating...

Exit Status: Normal Value: 0
1 5 buf:    Message left from: 30870

The value of i is:  1

Fork Instance:  2

Child Process (30871) Terminating...

Exit Status: Normal Value: 0
2 7 buf:    Message left from: 30871

The value of i is:  2

Fork Instance:  3

Child Process (30872) Terminating...

Exit Status: Normal Value: 0
3 9 buf:    Message left from: 30872

The value of i is:  3

Fork Instance:  4

Child Process (30873) Terminating...

Exit Status: Normal Value: 0
4 11 buf:   Message left from: 30873

The value of i is:  4

Parent Process (30868) Terminating...

With redirection

Generated separately; equivalent to, but distinct from, the Google doc image.

Fork Instance:  0

Child Process (30791) Terminating...

Fork Instance:  0

Exit Status: Normal Value: 0
0 3 buf:    Message left from: 30791

The value of i is:  0

Fork Instance:  1

Child Process (30792) Terminating...

Fork Instance:  0

Exit Status: Normal Value: 0
0 3 buf:    Message left from: 30791

The value of i is:  0

Fork Instance:  1

Exit Status: Normal Value: 0
1 5 buf:    Message left from: 30792

The value of i is:  1

Fork Instance:  2

Child Process (30793) Terminating...

Fork Instance:  0

Exit Status: Normal Value: 0
0 3 buf:    Message left from: 30791

The value of i is:  0

Fork Instance:  1

Exit Status: Normal Value: 0
1 5 buf:    Message left from: 30792

The value of i is:  1

Fork Instance:  2

Exit Status: Normal Value: 0
2 7 buf:    Message left from: 30793

The value of i is:  2

Fork Instance:  3

Child Process (30794) Terminating...

Fork Instance:  0

Exit Status: Normal Value: 0
0 3 buf:    Message left from: 30791

The value of i is:  0

Fork Instance:  1

Exit Status: Normal Value: 0
1 5 buf:    Message left from: 30792

The value of i is:  1

Fork Instance:  2

Exit Status: Normal Value: 0
2 7 buf:    Message left from: 30793

The value of i is:  2

Fork Instance:  3

Exit Status: Normal Value: 0
3 9 buf:    Message left from: 30794

The value of i is:  3

Fork Instance:  4

Child Process (30795) Terminating...

Fork Instance:  0

Exit Status: Normal Value: 0
0 3 buf:    Message left from: 30791

The value of i is:  0

Fork Instance:  1

Exit Status: Normal Value: 0
1 5 buf:    Message left from: 30792

The value of i is:  1

Fork Instance:  2

Exit Status: Normal Value: 0
2 7 buf:    Message left from: 30793

The value of i is:  2

Fork Instance:  3

Exit Status: Normal Value: 0
3 9 buf:    Message left from: 30794

The value of i is:  3

Fork Instance:  4

Exit Status: Normal Value: 0
4 11 buf:   Message left from: 30795

The value of i is:  4

Parent Process (30789) Terminating...

Code

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_NUM 5

int main ()
{

char buf [100];
memset(buf, 0, sizeof buf);
int ret;
pid_t pid;

int mypipefd [MAX_NUM][2]; 


for (int i = 0; i < MAX_NUM; i++)
{
    ret = pipe(mypipefd[i]);

    if (ret == -1)
    {
    perror("\nPipe Error... Exiting\n");
    exit(1);
    }
}

for (int i = 0; i < MAX_NUM; i++)
{
  printf ("\nFork Instance:\t%d\n", i); //Removing trailing \n changes output
    pid = fork();
    if ( pid == -1)
    {
        perror("\nFork Error... Exiting\n");
        exit(1);
    }

    else if (pid == 0)
    {
        int dupRes = dup2(0, mypipefd[i][0]);
        if (dupRes == -1)
        {
            perror("\nDup2 Error... Exiting\n");
            exit(1);
        }
        close(mypipefd[i][0]); // Redundant?

        pid_t childID = getpid();

        char testString [50];
        sprintf(testString, "%s%ld", "Message left from: ", (long) childID );

    ssize_t writeResult =  write(mypipefd[i][1], testString,    strlen(testString));
    if (writeResult == -1)
      {
    perror("\nWriting Error... Exiting\n");
    exit(1);
      }
        printf("\nChild Process (%ld) Terminating...\n", (long) childID);

        return 0;
    }

    else
    {

 //Credit to:  Paul Griffiths [http://stackoverflow.com/questions/35471521/waitstatus-wexitstatusstatus-always-returns-0]
    int status;
    if ( waitpid( pid, &status, 0 ) != -1 ) 
        {
            if (WIFEXITED(status))
            {
                int retval = WEXITSTATUS(status);
                printf("\nExit Status: Normal\tValue: %d",retval);
            }

            else if (WIFSIGNALED(status))
            {
                int retSig = WTERMSIG(status);
                printf("\nExit Status:\tSignal Exit\tValue:\t%d",retSig);
            }

            else if (WIFSTOPPED(status))
            {
                int retSig = WSTOPSIG(status);
                printf("\nExit Status:\tStop\tValue:\t%d",retSig);
            }

            else
            {
                perror("\nExit Status:WAIT PID UNKNOWN INSTANCE... Terminating\n");
                exit(1);
            }
        }

        close(mypipefd[i][1]); 
        ssize_t readResult = read(mypipefd[i][0], buf, 100);
        if (readResult == -1)
        {
        perror("\nRead Error... Exiting\n");
        exit(1);
        }           
        printf("\n%d %d buf:\t%s\n", i, mypipefd[i][0], buf);
        memset(buf, 0, sizeof buf);
        printf("\nThe value of i is:\t%d\n",i);

    }
}


pid_t parentID = getpid();
printf("\nParent Process (%ld) Terminating...\n", (long) parentID);



return 0;
}
User9123
  • 1
  • 2
  • No external links please. We are not going to click some random links. Please paste the output directly into the question. – kaylum Feb 17 '17 at 02:53
  • Please use the *Add Image* button and upload your images properly to imgur using that button. The links you've posted are not usable or fixable here. When you do so, please try to be careful and not upset the formatting I've done. :-) – Ken White Feb 17 '17 at 02:53
  • Okay guys, I'll give it a go. My files were hosted on google drive (you don't even have to download it to preview it). But I can't go ahead and try to upload as images here. The output can also be generated by running the program. I am unable to add images, I do not have enough reputation. @KenWhite Thanks for paragraphs. – User9123 Feb 17 '17 at 02:55
  • Any chance `sprintf(testString, "%s%ld", "Message left from: ", (long) childID );` overfills `testString`? – chux - Reinstate Monica Feb 17 '17 at 03:10
  • `read(mypipefd[i][0], buf, 100); printf("\n%d %d buf:\t%s\n", i, mypipefd[i][0], buf);` looks like a problem as `write(mypipefd[i][1], testString, strlen(testString));` does not write a null character. Use the return value of `read()`. – chux - Reinstate Monica Feb 17 '17 at 03:12
  • Chux I will look into your suggestions now. I do not understand why that would cause an error in one instance (redirecting) and not the other. – User9123 Feb 17 '17 at 03:17
  • We're not going to compile and run your code to figure out what you're asking. If you can't do it as images, copy the output from your screen to the clipboard and paste it in as text. – Ken White Feb 17 '17 at 03:20
  • Note that each of the five child processes has 5 pipes it can choose to use. If they were going to be long running, or running in parallel, you'd need to close both ends of the 4 unwanted pipes as well as the read end of the wanted pipe (which you do close, though you have a comment asking if it is redundant — strictly, it isn't, though it wouldn't cause much trouble here). – Jonathan Leffler Feb 17 '17 at 03:20
  • @chux I have added a check for the write and read return values. Neither returns an error value. I will update my code to include those checks. Ken I will add the output at the bottom. It is rather long, that is why I avoided including it in the OP. – User9123 Feb 17 '17 at 03:28
  • @JonathanLeffler, thank you very much for editing that in for me. – User9123 Feb 17 '17 at 03:28
  • I'm pretty sure the problem is the same as [`printf()` anomaly after `fork()`](http://stackoverflow.com/questions/2530663/printf-anomaly-after-fork/). The second child has some of the information in its standard output buffer that the parent has 'printed' but has not flushed. Adding `fflush(stdout)` at the top or bottom of the loop fixes it. – Jonathan Leffler Feb 17 '17 at 03:33
  • @JonathanLeffler Thank you for your reply. I will give that a try now. – User9123 Feb 17 '17 at 03:34
  • @JonathanLeffler Thank you for your suggestion. Flushing did help cut down on a lot of the code. But did not fully resolve the issue. I will play around with it more to see if adding additional flushes resolves my issue. – User9123 Feb 17 '17 at 03:40
  • I put the `fflush()` after the `printf ("\nFork Instance:\t%d\n", i);` line and before the `pid = fork();` line. Give or take PIDs, that gave me the same output as the no-redirection program. If you put the `fflush()` before the `printf()`, the `Fork Instance` messages should be repeated; I got 10 more lines of output compared with after. It's a good idea to ensure there's no pending (unflushed) output before forking. – Jonathan Leffler Feb 17 '17 at 03:42
  • Yep, the issue was I didn't add it after the fork instance line. I was also premature to reply, I should have thoroughly read the other thread. Thank you very @JonathanLeffler for helping me resolve my issue. The last question I have (which I don't know if the other thread answered) is why I experienced this error only when redirecting my output. I was under the impression that the redirection operator simply redirects and there is nothing fancy behind the scenes taking place. Is this thread the appropriate place to discuss that, or should I open a new thread? Thanks again! – User9123 Feb 17 '17 at 03:46
  • It's buffering. When the output is connected to a terminal, it's line buffered; when a newline is printed, the output is flushed to the terminal. When the output is not a terminal, it can be (and in fact is) fully buffered; the C library only flushes standard output to the non-terminal when the buffer is full. You can override that with `setvbuf()` called at the start. Or you can use `fflush()` carefully. You would have had a smaller problem if you'd started all five child processes and only then waited for them to write to you and die. Your synchronous operation exacerbated the problem. – Jonathan Leffler Feb 17 '17 at 03:50
  • @JonathanLeffler Thanks again for all the great info. All my questions have been answered. – User9123 Feb 17 '17 at 03:51

0 Answers0