6 Replies - 7420 Views - Last Post: 25 April 2010 - 08:53 PM Rate Topic: -----

#1 jbedo465  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 24
  • Joined: 18-February 10

Blocked Reading from a Pipe in C

Posted 25 April 2010 - 07:02 PM

Hi all,
I have a quick question about reading from and unnamed pipe in C. I'm forking multiple processes which write to a pipe(using a 2-dimensional array). However, when my parent process tries to read the pipe for each child, it will hang while it waits for a child to write to the pipe. Because I am running multiple processes which are writing multiple messages to a pipe, I want to read them as they come until all pipes are finished(the child processes close their pipes when they are done). So, my question is, how do I stop the read from blocking every time it waits for a child to write? My read looks like this:
 //loop through pipes and read them
  while(allDone != numChild){
    errCheck = read(fd[j][0], line, MAXLINE);

    if(errCheck == 0){
      allDone++;
      close(fd[j][0]);
      wait(&status);
    }

    if(errCheck > 0){
      printf("%s\n", line);
    }

    j++;
    if(!(j < numChild))
      j = 0;
  }



Thank you for the consideration,
JB

This post has been edited by jbedo465: 25 April 2010 - 07:02 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Blocked Reading from a Pipe in C

#2 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 5951
  • View blog
  • Posts: 23,214
  • Joined: 23-August 08

Re: Blocked Reading from a Pipe in C

Posted 25 April 2010 - 07:34 PM

Been a long time, but I think you can open the pipes in non-blocking mode and use a select call to process data only where it's there to be processed. If I'm understanding the issue correctly.
Was This Post Helpful? 0
  • +
  • -

#3 jbedo465  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 24
  • Joined: 18-February 10

Re: Blocked Reading from a Pipe in C

Posted 25 April 2010 - 07:42 PM

That sounds right. I've been looking but can't find how to do this. I know you can open a file using O_NONBLOCK, but don't know how to do this with an unnamed pipe. Here is my pipe call:
 for(k = 0; k < numChild; k++){
      if(pipe(fd[k]) < 0){
        perror("Pipe failed");
        exit(-1);
      }
    }


Thank you,
JB
Was This Post Helpful? 0
  • +
  • -

#4 noclaf  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 26
  • View blog
  • Posts: 94
  • Joined: 18-April 10

Re: Blocked Reading from a Pipe in C

Posted 25 April 2010 - 07:55 PM

Assuming you're on Linux, glibc defines a library of unlocked stdio calls. Check out unlocked_stdio(3).
Was This Post Helpful? 0
  • +
  • -

#5 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 5951
  • View blog
  • Posts: 23,214
  • Joined: 23-August 08

Re: Blocked Reading from a Pipe in C

Posted 25 April 2010 - 08:27 PM

Here is a quick example I threw together, based on man page examples.

#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int
main(int argc, char *argv[])
{
    int pfd[2] = { -1, -1 };
    pid_t cpid;

    assert(argc == 2);
    if (pipe(pfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
    fcntl(pfd[0], F_SETFL, O_NONBLOCK);
    cpid = fork();
    if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }

    if (cpid == 0)
    {
        /* Child writes to pipe */
        printf("Child waiting 5 seconds for write\n");
        sleep(5);
        close(pfd[0]);          /* Close unused read end */

        printf("Child writing to pipe\n");
        write(pfd[1], argv[1], strlen(argv[1]));
        write(pfd[1], "\n", 1);
        sleep(1);
        int i = 1;
	char buffer[16] = { 0 };
        for (; i <= 10; ++i)
	{
            sprintf(buffer, "sleeping %d\n", i) ;
            if (write(pfd[1], buffer, strlen(buffer)) == -1)
                break;
            sleep(i);
        }
        write(pfd[1], "Done!\n", strlen("Done!\n"));
	close(pfd[1]);
	_exit(EXIT_SUCCESS);
    }
    else
    {
     	/* Parent reads client data from pipe */
	/* Close unused write end */
	close(pfd[1]);

	fd_set fds;
	struct timeval tv = { 0 };
	tv.tv_sec = 6; // Six second timeout, modify this to see timeout        

	FD_ZERO(&fds); // zero-out the file descriptor set                      

	char buffer[BUFSIZ] = { 0 };
	while (1)
            size_t bytesRead = 0;
            FD_SET(pfd[0], &fds); // add our read file descriptor to the set    

            // First param to select is the HIGHEST fd in our set + 1.          
            // That +1 is very important!                                       
            int rv = select(pfd[0] + 1, &fds, NULL, NULL, &tv);
            if (rv == -1)
                perror("select");
            else if (rv == 0)
                printf("Timeout!\n");
            else
            {
                if (FD_ISSET(pfd[0], &fds))
                {
                    bytesRead = read(pfd[0],
                                     buffer,
                                     sizeof(buffer));
                    if (bytesRead == 0)
                    {
                        printf("Client closed write end\n");
                        break;
                    }
                }
            }
            if (bytesRead > 0)
            {
                buffer[bytesRead] = 0;
                if (strlen(buffer) > 0)
                    printf("Received %s", buffer);
            }
            FD_CLR(pfd[0], &fds);

        }

        close(pfd[0]);          /* Reader will see EOF */
        wait(NULL);             /* Wait for child */
        exit(EXIT_SUCCESS);
    }
}


Was This Post Helpful? 0
  • +
  • -

#6 noclaf  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 26
  • View blog
  • Posts: 94
  • Joined: 18-April 10

Re: Blocked Reading from a Pipe in C

Posted 25 April 2010 - 08:39 PM

View PostJackOfAllTrades, on 25 April 2010 - 07:27 PM, said:

Here is a quick example I threw together, based on man page examples.

    assert(argc == 2);
    if (pipe(pfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
    fcntl(pfd[0], F_SETFL, O_NONBLOCK);
    ....


Good catch. However, you're clobbering any current flags on the pipe when you set it this way. Not knowing what's in there, it's best to fetch the flags first and bitwise-or in the extra juicy bits.

int flags;
flags = fcntl(pfd[0], F_GETFL);
fcntl(pfd[0], F_SETFL, flags | O_NONBLOCK);


You may want to check the return value on the call that sets the flags, because it can fail. Man page shows a return of -1 is failure and anything else is success.
Was This Post Helpful? 1
  • +
  • -

#7 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 5951
  • View blog
  • Posts: 23,214
  • Joined: 23-August 08

Re: Blocked Reading from a Pipe in C

Posted 25 April 2010 - 08:53 PM

Good on ya, noclaf. You're quite right...it could be more robust. :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1