Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Print in order of termination?

I've got a program which generates a random number, n, then loops n times.

On each iteration, it randomizes the value of sleeptime, and calls fork. The child process sleeps for sleeptime seconds, then exits with the value of the index variable.

The parent then loops again, waiting for each process to terminate. As each process terminates, I'm trying to log out the pid and childid of the process, but this is where I'm running into trouble. The pids are printing in order, and childid is remaining at 0.

What am I doing wrong?

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

    //  Wire up the timer
    long time = elapsedTime(0);

    /*  Generate a random number between MINFORKS and MAXFORKS
     */
    unsigned int seed = generateSeed(0);
    int n = rand_r(&seed) % MAXFORKS + MINFORKS-1;

    /*  Log next step
     */
    time = elapsedTime(1);
    printf("%li: Number of forks = %i\n", time, n);

    /*  Hang on to the PIDs so we can wait for them after forking
     */
    pid_t *PIDs = (pid_t *)(malloc(sizeof(*PIDs)*n));


    /*  Fork n times
     */
    for (int i = 0; i < n ; i++)
    {
        /*  Call fork() and retain the returned identifier
         */
        pid_t processIdentifier = fork();

        /* Randomize the child sleep time
         */
        seed = generateSeed(0);
        int sleeptime = rand_r(&seed)  % MAXPAUSE + MINPAUSE;

        /*  Check for errors
         */
        if (processIdentifier == -1) {
            printf("Error: %i", errno);
        }


        if (!processIdentifier)
        {
            /*  We're in the child process,
             *  sleep and then exit with
             *  i as the error code.
             */

            usleep(sleeptime);
            _exit(i);
        }
        else
        {
            /*  We're in the parent:
             *  Store the PID and
             *  print out the results.
             */

            PIDs[i] = processIdentifier;

            time = elapsedTime(1);
            printf("%li: Child %i, pid = %i, forked, waits %i usec\n", time,  i, processIdentifier, sleeptime);

        }
    }

    /* Log next step
     */
    time = elapsedTime(1);
    printf("%li: Finished forking, going to wait.\n", time);

    /*
     *  Loop through the processes and wait for them
     *  to terminate. Then print the childid, and the
     *  the pid.
     */

    for (int i = 0; i < n; i++)
    {

        /*  Get the PID we want to track
         */
        pid_t pid = PIDs[i];

        /*  Wait for the child process
         *  and grab it's status info
         */
        int status = NULL;


        waitpid(pid, &status, 0);

        int childid = -1;
        if(WIFEXITED(status))
        {
            childid = WTERMSIG(status);
        }

        /*  Log the results
         */
        time = elapsedTime(1);
        printf("%li: Child %i, pid = %i, terminated\n", time, childid, pid);
    }

    /*  All done!
     */
    time = elapsedTime(1);
    printf("All done. It only took %li milliseconds!", time);   
}

Disclaimer, this is homework (link here, may disappear at any time), but I've already done almost all of it. I'm just having trouble grasping this one aspect of it.

like image 408
Moshe Avatar asked May 24 '13 20:05

Moshe


Video Answer


2 Answers

Your code is waiting on the pids in the order you are providing them in your successive waitpid() calls. If you pass -1 in as the first parameter to waitpid() instead (or if you just call wait()), you will get the first child that the kernel informs you about, rather than the one you specifically asked to be notified about. Check the return value to see which child it was (or if an error occurred).

The childid stays 0 because you are are extracting WTERMSIG from the wait status, rather than WEXITSTATUS.

like image 127
jxh Avatar answered Sep 29 '22 00:09

jxh


for (int i = 0; i < n; i++)
{
    pid_t pid = PIDs[i];
    int status = NULL;
    waitpid(pid, &status, 0);

So first it waits for the first process to end, and then prints the information from that process.
Then it it waits for the second process to end, and then prints the information from that process.
Then it it waits for the third process to end...

And you're wondering why they're being reported in order?

pass -1 to waitpid instead, which this page says will cause it to wait for any child thread instead of specific thread.

Also, right before printing, you have int childid = -1;. Not sure why.

like image 22
Mooing Duck Avatar answered Sep 29 '22 00:09

Mooing Duck