views:

195

answers:

3

I'm working on an application for Linux in C which uses multiple threads. The threads which are spawned by the main function do most of the work, and therefore usually finish last. I'm seeing some strange behavior, and I believe it's due to the main thread terminating before the spawned threads have a chance to finish their jobs. Here's some sample code to illustrate what I'm talking about:

#define _POSIX_C_SOURCE 200112L
#define _ISOC99_SOURCE
#define __EXTENSIONS__
#define _GNU_SOURCE

#include <pthread.h>
#include <stdio.h>

void
my_cleanup(void *arg)
{
     printf("cleanup: %s\n", (char *)arg);
}


void *
thread_stuff(void *arg)
{
     printf("thread started\n");
     pthread_cleanup_push(cleanup, "running");
     if (arg)
          pthread_exit((void *)2);
     pthread_cleanup_pop(0);
     pthread_exit((void *)2);
}


int
main()
{
     int err;
     pthread_t tid1, tid2;

     err = pthread_create(&tid1, NULL, thread_stuff, (void *)1);
     err = pthread_create(&tid2, NULL, thread_stuff, (void *)1);

     sleep(10);                 /* change the value here if you want */

     return SUCCESS;
}

When this code is run, the message from the cleanup function is printed twice, as it should be, but other times when it is run, I see the message printed only once sometimes, and other times I see it printed three times or not at all. You add in the sleep function in the main function to play with how long it takes the main function to terminate.

What can I do to make the program run as it should? I suspect it has something to do with joining to the children, but I don't entirely understand the concept of a join or how to apply it to this situation.

Thanks in advance!

+2  A: 

Yes, you should "join" the threads. "Joining" a thread simply means waiting until the thread has terminated. In other words, you would do

pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

to wait until both threads have terminated.

Edit: What to do if you have a child thread which, in turn, creates a "grandchild" thread? As a rule, whoever created the thread should wait for it to terminate ("join" it). So in this scenario, the child thread would call phtread_join on the grandchild thread, and the main thread would call join on the child thread.

Martin B
Thanks! do I need to join on all threads I create? what if I have a thread which creates a thread? how do I join on this "grand-child" thread?
Carl
@Carl: I've edited my answer to discuss this case.
Martin B
Note that if you don't intend to ever use `pthread_join`, you can also use `pthread_detatch` to eliminate the memory leak you'd have otherwise. However, you won't know when the thread terminates then.
bdonlan
+2  A: 

I think you want to run pthread_join on each of the threads when your main thread completes -- this makes the main thread stop until the given thread finishes running. Other threads can still complete first though, so running pthread_join on every thread will prevent the main thread from terminiating until all of the others have terminated.

Ken Bloom
A: 

When should pthread_join be called? Should it be called right after a new thread is spawned? Or should I wait until the end of the function which created the thread, or perhaps even the end of the main function before calling it? What if N threads are being spawned where N is a number that is not known until runtime. Is there a recommended way to keep track of all the thread ids of the created processes so they can be joined later (assuming it's recommended to wait until later to join, and not to join immediately.)

Thanks again! -- Carl

Carl
In C, you'll need to keep track of each spawned thread id in order to join with them all at the end of your main function.
Keith Randall