nik
nik

Reputation: 8725

Strange behavior of this simple pthread code

If I'll compile and run the code below

  1 #include <iostream>
  2 #include <pthread.h>
  3 #include <cstdio>
  4 #include <cstdlib>
  5
  6 #define NTHREADS 4
  7 #define N 100
  8 #define MEGEXTRA 1000000
  9
 10 using namespace std;
 11
 12 pthread_attr_t attr;
 13
 14 void *doWork (void *threadid) {
 15     double A[N][N];
 16     int tid = *(reinterpret_cast<int *>(threadid));
 17     size_t myStackSize;
 18     pthread_attr_getstacksize (&attr, &myStackSize);
 19     cout << "Thread " << tid << ": stack size = " << myStackSize << " bytes" << endl;
 20
 21     for (int i = 0; i < N; i++) {
 22         for (int j = 0; j < N; j++) {
 23             A[i][j] = ((i * j) / 3.452) + (N - 1);
 24         }
 25     }
 26
 27     pthread_exit (NULL);
 28 }
 29
 30 int main () {
 31     pthread_t threads[NTHREADS];
 32     size_t stackSize;
 33
 34     pthread_attr_init (&attr);
 35     pthread_attr_getstacksize (&attr, &stackSize);
 36
 37     cout << "Default stack size = " << static_cast<long>(stackSize) << endl;
 38
 39     stackSize = sizeof(double) * N * N + MEGEXTRA;
 40     cout << "Amount of stack needed per thread = " << static_cast<long>(stackSize) << endl;
 41
 42     pthread_attr_setstacksize (&attr, stackSize);
 43     cout << "Creating threads with stack size = " << static_cast<long>(stackSize) << endl;
 44
 45     int i[NTHREADS];
 46     for (int j = 0; j < NTHREADS; j++) {
 47         sleep(1);
 48         i[j] = j;
 49
 50         int rc = pthread_create(&threads[j], &attr, doWork, reinterpret_cast<void *>(&i[j]));
 51         if (rc) {
 52            cout << "Error Code: " << rc << endl;
 53             exit (-1);
 54         }
 55     }
 56
 57     cout << "Created " << NTHREADS << " threads" << endl;
 58     pthread_exit(NULL);
 59 }

I get the following output:

Default stack size = 8388608
Amount of stack needed per thread = 1080000
Creating threads with stack size = 1080000
Thread 0: stack size = 1080000 bytes
Thread 1: stack size = 1080000 bytes
Thread 2: stack size = 1080000 bytes
Created 4 threads
Thread 3: stack size = 1080000 bytes

but if I'll comment out sleep(1); in line 47, I get following output

Default stack size = 8388608
Amount of stack needed per thread = 1080000
Creating threads with stack size = 1080000
Created 4 threads
Thread 3: stack size = 1080000 bytes
Thread 2: stack size = 1080000 bytes
Thread 1: stack size = 1080000 bytes
Thread 9251904: stack size = 1080000 bytes /** ERROR should be Thread 0: stack size = 1080000 /**

Can anyone explain what is going on? Why do I get incorrect output with sleep(1) commented out?

this is what I'm using to compile the code

g++ -Wall -Wextra -O2 -ggdb -pthread 5.cpp -o 5

Upvotes: 4

Views: 476

Answers (3)

That's because the main thread, the one that creates the others, exits (by the vertue of pthread_exit - and you're getting at the end of mainanyway) before all the created threads had the time to run. The i array gets destroyed and contains garbage at the time it is read by all the threads.

You have to wait - i.e. pthread_join - for your child threads before main can exit.

sleep buys you some time for the threads to execute, but it is still up to the OS to decide who runs when. It could happen that sleep(1) is enough, or not enough, or that nobody runs until the mailman has come and delivered.

Call pthread_join, and you'll be safe.

Upvotes: 5

When you comment out sleep(1); the main thread will create all threads in one go and presumably will be faster than the system spawning those threads. The threads themselves go concurrent so their output can in any arbitrary order. When you use sleep(1); the threads will be created, the main thread will wait for a second whilst this the created thread will be scheduled, run and output in far less than a second and then the next thread will be created.

The created 4 threads will be written as soon as the loop finishes. Without the sleep(1); this loops finishes immediately before any of the spawned threads can run, so it will come before the thread's outputs. With the sleep all threads except the last are past their output, when the loop is left so the Created 4 threads will come before the last created thread that was not yet scheduled.

Upvotes: 0

Ed Heal
Ed Heal

Reputation: 59987

You do not mention if it is a single core machine that you are using.

Why do you think it is the incorrect output?

The OS is free to process the threads in any order. The sleep will yield that thread and enable another thread a bash at the CPU. That is why the code will produce the output as indicated.

Upvotes: 1

Related Questions