views:

142

answers:

5

Hello, I am trying to understand pthreads by example. I have made the following code that is giving different answers everytime I run! Could anyone explain the bug please? TIA, Sviiya

The code is here:

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

#define NUM_THREADS 4

struct thread_data {
        int  thread_id;
        int  sum;
};

struct thread_data thread_data_array[NUM_THREADS];

void *PrintHello(void *threadarg)
{
        struct thread_data *my_data;
        int taskid;
        int sum;

        my_data = (struct thread_data *) threadarg;
        taskid = my_data->thread_id;
        sum = my_data->sum;

        printf("Hello World! It's me, thread #%d\n", taskid);

        return my_data;
}

int main ()
{
        pthread_t threads[NUM_THREADS];
        int rc;
        long t;
        int sum=0;

        for (t=0; t < NUM_THREADS; t++) {
                printf("Hi! %ld\n", t);

                threads[t] = t;

                thread_data_array[t].thread_id = t;
                thread_data_array[t].sum = sum;
                rc = pthread_create(&threads[t], NULL, PrintHello, (void *) &thread_data_array[t]);
        }

        return 0;
}

The output is here:

[user@office tmp]$ ./a.out 
Hi! 0
Hi! 1
Hello World! It's me, thread #0
Hello World! It's me, thread #1
Hi! 2
Hi! 3
Hello World! It's me, thread #2
[user@office tmp]$ ./a.out 
Hi! 0
Hi! 1
Hello World! It's me, thread #0
Hello World! It's me, thread #1
Hi! 2
Hi! 3
Hello World! It's me, thread #2
Hello World! It's me, thread #3
[user@office tmp]$ ./a.out 
Hi! 0
Hello World! It's me, thread #0
Hi! 1
Hello World! It's me, thread #1
Hi! 2
Hello World! It's me, thread #2
Hi! 3
Hello World! It's me, thread #3
[user@office tmp]$ ./a.out 
Hi! 0
Hi! 1
Hello World! It's me, thread #0
Hi! 2
Hi! 3
Hello World! It's me, thread #3
[user@office tmp]$
+1  A: 

If you mean the order of the answers, yes, it will be different since which thread runs is decided by the Linux scheduler.

To elaborate: Once you create your threads, the order in which they get CPU time depends on the underlying OS scheduler(here, Linux scheduler). This may not be the same everytime.

Amit
Nope. The number of threads actually created were 3, 4, 4, 2. Can't see why. :(
+4  A: 

There is no bug, this is just how threads work. Your main thread creates new threads, which are at that point "ready to run". At some point in time (determined by the OS), your main thread will be suspended and one of the other threads will run for a certain amount of time (usually a few tens of milliseconds). The system will keep switching between threads while there exist running threads for your program.

The exact point in time when your main thread will be interrupted and one of the other threads can print it's Hello World will depend on what the OS scheduler decides, based on how long your main thread is already running, other activity in the system, external (I/O) events, etc.

EDIT to include my comment below:

The reason why you're seeing 3, then 4, then only 2 "Hello Worlds", is that you created the threads, but you didn't wait for them to actually get scheduled and run. When your main loop ends, the program is dead, irrespective whether your other threads have had a chance to run. If you want all of your threads to be finished, you need to do a pthread_join on each of your threads before returning from main.

Wim
The number of threads actually created were 3, 4, 4, 2 but I expect all the threads to be created, isn't it?
You created the threads, but you didn't wait for them to actually run (at least once). When your `main` loop ends, the program is dead, irrespective whether your other threads have had a chance to run. You'll want to do a `thread_join` on each of your threads before returning from `main`, if you want all of your threads to be finished.
Wim
There might also be a flag in `pthread_create` that lets you tell the system that it should wait for this thread to finish before terminating the program, but I'm not sure what it's called...
Wim
Oh! Thanks, Wim! :)
Now I fixed the issue. Thanks. :)
+1  A: 

The reason you don't see the other threads executing, as per your comments to the other answers is because your main() function (and hence your program) returns before the other threads have had an opportunity to execute. If you put a sleep(5) before your main() returns, you will see them execute.

iWerner
Thanks iWerner. :)
+1  A: 

I agree with the other two answers.
It may also be worth noting that the process exits immediately after the creation of the threads. It will create all 4, but each may not have time enough to do anything before the program exits.

sinibar
Thank you sinibar. :)
A: 

Ok, finally added the extracode as suggested by the experts and it works fine now. Thanks again to all. :)

for ( t = 0; t < NUM_THREADS; t++ ) {
    (void) pthread_join(threads[t], NULL);
}