Linux, creating thread fails

sollala
sollala used Ask the Experts™
on
My following program works perfect on solaris, but failing on linux. I have red hat7.3. Any one seen such behavior?

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>

static int childpid = 0;

static void* theThread(void* lpParameter)
{
    int pid = fork();
    switch (pid)
    {
        case 0:
            printf("Child here... (pid = %d)\n", getpid());
            exit(99);
            break;
        case -1:
            fprintf(stderr, "Failed to fork, errno = %d\n", errno);
            exit(1);
        default:
            childpid = pid;
            break;
    }
    return 0;
}

static void sigchldHandler(int)
{
    printf("Got a signal!!!\n");
}


int main()
{
    signal(SIGCHLD, sigchldHandler);
    printf("Main process pid = %d\n", getpid());

    pthread_t t;
    pthread_create(&t, NULL, theThread, NULL);
    pthread_join(t, NULL);

    int status;
    printf("Parent here... (pid = %d, child pid = %d)\n",
           getpid(), childpid);
    if (waitpid(childpid, &status, 0) < 0)
        fprintf(stderr, "Failed to waitpid, errno = %d\n", errno);
    else if (WIFEXITED(status))
        printf("Child exited with status = %d\n",
               WEXITSTATUS(status));
    return NULL;

    return 0;
}


Error mesg :
Main process pid = 2370
Child here... (pid = 2373)
Got a signal!!!, pid = 2372
Parent here... (pid = 2370, child pid = 2373)
Failed to waitpid, errno = 10
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Commented:
I don't get the signal that you are, and I'm not an expert on the semantics of child signals, so I won't comment on that. However, I can explain why waitpid is not working.

First, a few superficial clarifications:

- You don't only have a child, but a child and a grandchild (The child's forked copy).
- errno=10 is a "No children" failure, by which waitpid() is complaining that the given child pid does not exist.
- Since threads are Lightweight processes in Linux (at least until Linux 2.5), each gets its own pid.

Here's what's happening.

A) You call pthread_create to create a thread for your function.  pthread first goes to create a control thread for its internal uses.  Assuming the main process (parent) is pid 2370, this means that the pthread control thread is pid 2371.  Next, the pthread control thread creates the child thread, which is allocated the next pid, namely 2372.   This thread's parent is the control thread: 2371. Now we have:
Parent, (pid = 2370, parent pid = ?)
Control thread, (pid = 2371, parent pid = 2370)
Child thread (pid = 2372, parent pid = 2371)
B) Your child thread forks, to create a grandchild. Now things are:
Parent, (pid = 2370, parent pid = ?)
Control thread, (pid = 2371, parent pid = 2370)
Child thread (pid = 2372, parent pid = 2371)
Grandchild thread (pid = 2373, parent pid = 2372)
C) The child and grandchild exit.  This relinquishes the pthread control thread, which exits as well.  The exiting of the grandchild process notifies its parent, namely the child process, or if it already died, the init process, that it died (But not the parent process).
Now things are back to:
Parent, (pid = 2370, parent pid = ?)
D) The parent prints the information.  The parent then waits for the grandchild, which never notifies it of its death, because its not its direct child.

Note that with Solaris this can work, because Solaris implements threads as their own entities under processes, while Linux implements them as processes that share resources.
In Solaris, you have:

+Process
  + Parent thread
    + Child thread
+Copy process with child thread running
  + Parent thread (not sure about the semantics of this thread in Solaris)
    + Child thread (This one runs and prints "Child here").

Note that fork() in the parent's thread in Solaris yields a new pid, that encapsulates ALL of the threads of the new process, so that when the new process dies, the main thread waits upon the right pid number.

+ One solution for you might be to have the same thread that forks be the one to wait for the death of the fork'ed grandchild process.
+ Another solution would be communicating with the dying process in other means (it gets reparented to the init process when its parent dies, so there are no (less?) worries about zombie processes, as init cleans them up).  Your new process could use System V msg queues or pipes to communicate with the main process.
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:
Recommendation: Accept Comment from Peaker

Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
 
DominicCronin
EE Cleanup Volunteer

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial