• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3309
  • Last Modified:

how to use non-blocking wait pid, and avoid zombie processes

Hey, I was just wondering how we were supposed to use non-blocking waitpid's, I've read http://linux.die.net/man/2/waitpid a few times, and the flags:

< -1 - meaning wait for any child process whose process group ID is equal to the absolute value of pid.
-1 - meaning wait for any child process.
0 - meaning wait for any child process whose process group ID is equal to that of the calling process.
> 0 - meaning wait for the child whose process ID is equal to the value of pid.

My program generates a thread that has a somewhat infinite loop in it, but since it is a thread, it is supposed to return to the main program in a bit and print the prompt right? Or is it completely dependent on the system?
pid = fork();
      if(strcmp(second_string, "off") == 0)
        pthread_cancel(tid);
      else if ( pid == 0 ) { /* child process */
        pthread_attr_init(&attr);
        thread_c = pthread_create(&tid,&attr,watch,second_string);
        if(thread_c != 0){
          perror("Thread");
        }
        pthread_join(tid,NULL);
      }
      else if ( pid > 0 ) { /* parent process */
        waitpid(pid, &status, 1);
      }

Open in new window

0
errang
Asked:
errang
  • 15
  • 11
1 Solution
 
mrjoltcolaCommented:
I'm not sure why you are mixing threads and fork, but since you are, make sure your processes exit when they are done. Your code snippet shows the child process creating a thread, then waiting for the thread to exit. I don't know why you do it this way, there is no need for a thread at all, in that case. But, after the pthread_join() where does your child continue to? There is no exit() in your code snippet, so I cannot tell.

Also, zombies are not a product of the pthread API, but the forking. When your thread routine returns, it will "go away" or exit, but the parent thread does not.

Suffice to say, I think you are making the code more complex by mixing threading and forking.

So what exactly is your question?
0
 
errangAuthor Commented:
My question is, in my shell, when I say watchmail watch.txt, my program just stalls forever, I just tried putting an exit(1) in the thread.

This is actually the same program from the previous question... with a different problem.. =(.

pid = fork();
      if(strcmp(second_string, "off") == 0)
        pthread_cancel(tid);
      else if ( pid == 0 ) { /* child process */
        pthread_attr_init(&attr);
        thread_c = pthread_create(&tid,&attr,watch,second_string);
        if(thread_c != 0){
          perror("Thread");
        }
        pthread_join(tid,NULL);
        exit(1);
      }
      else if ( pid > 0 ) { /* parent process */
        waitpid(pid, &status, 2);
      }

void *watch(void *time){
  char *filename = (char *) time;

  struct stat watch_mail;
  int status, slp;
  time_t old_time, new_time;

  //fprintf(stderr, "I am here...\n");

  status = stat(filename, &watch_mail);
  //printf("status = %d", status);
  old_time = watch_mail.st_mtime;

  while(1){
    status = stat(filename, &watch_mail);
    new_time = watch_mail.st_mtime;

    if(old_time!=new_time){
      printf("\a\aThis file has been modified at time %s", ctime(&new_time));
      break;
    }

    slp = sleep(5);
  }
}

If I shouldn't use thread's and fork at the same time... how else could I do this?
0
 
errangAuthor Commented:
Sorry, forgot to include the output I get:

> ./mysh
/home/usra/7e/32407/cisc361/project#2>watchmail watch.txt
^Z
Suspended



0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
mrjoltcolaCommented:
>>If I shouldn't use thread's and fork at the same time... how else could I do this?

Your code snippet for the child does:

      else if ( pid == 0 ) { /* child process */
        pthread_attr_init(&attr);
        thread_c = pthread_create(&tid,&attr,watch,second_string);
        if(thread_c != 0){
          perror("Thread");
        }
        pthread_join(tid,NULL);
        exit(1);
      }

1) You create a child _process_
2) The child _process_ creates a child _thread_ that does the work, then returns
3) The child _process_ exits

So skip the middleman, and just make the child _process_ do the work, then exit. Since child _process_ does nothing but wait on a worker thread, why use a thread?
0
 
mrjoltcolaCommented:
And regarding zombie processes, I recommend using a signal handler for SIGCHLD, and calling waitpid() WNOHANG inside the handler. That way it is asynchronous and does not clutter your primary thread/process with the waitpid() call.
0
 
errangAuthor Commented:
Ok... something like this?

pid = fork();
      if(strcmp(second_string, "off") == 0)
        pthread_cancel(tid);
      else if ( pid == 0 ) { /* child process */
        status = stat(second_string, &watch_mail);

        //printf("status = %d", status);
        old_time = watch_mail.st_mtime;

        while(1){
          status = stat(second_string, &watch_mail);
          new_time = watch_mail.st_mtime;

          if(old_time!=new_time){
            printf("\a\aThis file has been modified at time %s", ctime(&new_time));
            break;
          }

          slp = sleep(5);
        }
        exit(1);
      }
      else if ( pid > 0 ) { /* parent process */
        waitpid(pid, &status, 2);
      }

0
 
errangAuthor Commented:
>>And regarding zombie processes, I recommend using a signal handler for SIGCHLD, and calling waitpid() WNOHANG inside the handler. That way it is asynchronous and does not clutter your primary thread/process with the waitpid() call.

signal handler? You mean this? http://linux.die.net/man/2/signal
0
 
mrjoltcolaCommented:
Yes, I think so. You might factor the code out into a "watchmail()" function, but you have the right idea. So now there is no threading to worry about, though you still have a pthread_cancel() in the parent process.
0
 
errangAuthor Commented:
and... would I need to change a lot of things for sighandler to work...? this thing's due in 11 hours =(
0
 
errangAuthor Commented:
>>though you still have a pthread_cancel() in the parent process.

OH yeah... that's why I had a thread, my watchmail is supposed to turn itself off if I say watchmail off...
0
 
errangAuthor Commented:
But this thing still doesn't show the prompt for the shell after running watchmail though =(
0
 
mrjoltcolaCommented:
0
 
mrjoltcolaCommented:
So put a debugging statement _inside_ the while loop to see what is going on.

        while(1){
          status = stat(second_string, &watch_mail);
          new_time = watch_mail.st_mtime;
 
          if(old_time!=new_time){
            printf("\a\aThis file has been modified at time %s", ctime(&new_time));
            break;
          }
          else
            fprintf(stderr, "Nothing happening, going to sleep for 5.\n");
 
          slp = sleep(5);
        }

Open in new window

0
 
errangAuthor Commented:
Ok, put that in, and it just keeps printing the sleep message, or it, exits and never bothers checking that file again...
 pid = fork();
      if(strcmp(second_string, "off") == 0)
        pthread_cancel(tid);
      else if ( pid == 0 ) { /* child process */
        status = stat(second_string, &watch_mail);
 
        //printf("status = %d", status);
        old_time = watch_mail.st_mtime;
 
        while(1){
          status = stat(second_string, &watch_mail);
          new_time = watch_mail.st_mtime;
 
          if(old_time!=new_time){
            printf("\a\aThis file has been modified at time %s", ctime(&new_time));
            break;
          }
          else{
            fprintf(stderr, "nothing's happening going to zzzzzzzzzzzz.\n");
            exit(1);
          }
        }
        exit(1);
      }
      else if ( pid > 0 ) { /* parent process */
        waitpid(pid, &status, 2);
      }

Open in new window

0
 
errangAuthor Commented:
sorry... forgot to include output again

This one is without an exit(1);

/home/usra/7e/32407/cisc361/project#2>watchmail zz.txt
nothing's happening going to zzzzzzzzzzzz.
nothing's happening going to zzzzzzzzzzzz.
nothing's happening going to zzzzzzzzzzzz.
nothing's happening going to zzzzzzzzzzzz.
nothing's happening going to zzzzzzzzzzzz.
nothing's happening going to zzzzzzzzzzzz.
nothing's happening going to zzzzzzzzzzzz.
^Z
Suspended

with an exit(1)
> ./mysh
/home/usra/7e/32407/cisc361/project#2>watchmail zz.txt
nothing's happening going to zzzzzzzzzzzz.
/home/usra/7e/32407/cisc361/project#2>echo hi > zz.txt
works 2
/home/usra/7e/32407/cisc361/project#2>

0
 
errangAuthor Commented:
I might be exceptionally dense right now.. but I'm juggling 2 projects at the moment... so I might not see something obvious... I'm sorry if I missed something and am asking redundant questions..
0
 
mrjoltcolaCommented:
So it seems the file you are stating never gets modified. Are you modifying the file timestamp during your testing, you should be. Try using the "touch" command.
0
 
errangAuthor Commented:
I am modifying the timestamp.



while(1){
          status = stat(second_string, &watch_mail);
          new_time = watch_mail.st_mtime; <---- constantly checks the time of the file
 
          if(old_time!=new_time){ <--- compares old time with new time
            printf("\a\aThis file has been modified at time %s", ctime(&new_time));
            break;
          }

Open in new window

0
 
errangAuthor Commented:
The problem is... once I call the command it constantly keeps checking it, and stays in that silly loop, and if I call exit, it completely exits and never checks the file again... I'm not sure what to do.
0
 
mrjoltcolaCommented:
>>I am modifying the timestamp.

How?
0
 
mrjoltcolaCommented:
Perhaps you should print out the st_mtime each loop also. Add more debugging to narrow down to the problem.
0
 
errangAuthor Commented:
Well, I do kinda know that its working, because when I changed the file I was watching through another shell, this thing beeped and said the file changed at so and so time...

But sure,

Here's the output:

> cc testwatch.c
> ./a.out
old time = Mon Apr 27 15:13:16 2009
new time = Mon Apr 27 15:13:16 2009
old time = Mon Apr 27 15:13:16 2009
new time = Mon Apr 27 15:13:16 2009
old time = Mon Apr 27 15:13:16 2009
new time = Mon Apr 27 15:13:16 2009
old time = Mon Apr 27 15:13:16 2009
new time = Mon Apr 27 15:14:30 2009  <--------------------------------------\
This file has been modified at time Mon Apr 27 15:14:30 2009 <---\ See, it works


//And the program
 
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <pthread.h>
 
void *watch(void *time);
 
int main(){
  int status;
  int thread_c = 0;
  pid_t pid = 0;
  pthread_t tid;
  pthread_attr_t attr;
  
  pid = fork();
  if ( pid == 0 ) { /* child process */
    pthread_attr_init(&attr);
    thread_c = pthread_create(&tid,&attr,watch,"zzz.txt");
    if(thread_c != 0){
      perror("Thread");
    }
    pthread_join(tid,NULL);
   }
  else if ( pid > 0 ) { /* parent process */
    waitpid(pid, &status, 2);
  }
}
void *watch(void *time){
  char *filename = (char *) time;
 
  struct stat watch_mail;
  int status, slp;
  time_t old_time, new_time;
 
  //fprintf(stderr, "I am here...\n");
 
  status = stat(filename, &watch_mail);
  //printf("status = %d", status);
  old_time = watch_mail.st_mtime;
 
  while(1){
    status = stat(filename, &watch_mail);
    new_time = watch_mail.st_mtime;
 
    printf("old time = %s", ctime(&old_time));
    printf("new time = %s", ctime(&new_time));
 
    if(old_time!=new_time){
      printf("\a\aThis file has been modified at time %s", ctime(&new_time));
      break;
    }
 
    slp = sleep(5);
  }
}

Open in new window

0
 
mrjoltcolaCommented:
So what is the problem? I see you have returned to using a thread, why? Once the child process is done, it just needs to exit.
0
 
errangAuthor Commented:
The problem is.. I need another window to modify the file I'm watching, I can't do it from the running program.
0
 
errangAuthor Commented:
The infinite loop... is going on indefinitely, all sleep is doing is slowing it down, but not halting it.
0
 
mrjoltcolaCommented:
You can't use 2 windows? What sort of login program are you using?

Run it in the background with & if you have to. I still don't see how a thread helps. fork is good enough.

Replace the break with an exit and see what happens.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 15
  • 11
Tackle projects and never again get stuck behind a technical roadblock.
Join Now