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

const int kMaxThreads = 10;

void * threadRoutine(void * threadArg) {
    int myThreadNumber = * ((int * ) threadArg);
    //(int)threadArg
    printf("threadRoutine()=>: this is thread number %d!\n", myThreadNumber);
    int sleepTime = random() % 20;
    sleep(sleepTime);
    printf("threadRoutine()=>: thread[%d] completed after sleeping %d [secs]!\n",
        myThreadNumber, sleepTime);
    pthread_exit((void * ) myThreadNumber);
}

int main(int argc, char * argv[]) {
    pthread_t threads[kMaxThreads];
    printf("main()=>: creating threads...\n");
    for (int jj = 0; jj < kMaxThreads; jj++) {
        if (pthread_create( & threads[jj], NULL, threadRoutine, (void * ) jj) != 0) {
            /* undefined reference to a pthread_create*/
        } else {
            printf("main()=>: created thread[%d]!\n", jj);
        }
    }
    printf("main()=>: waiting for threads to complete...\n");
    for (int jk = 0; jk < kMaxThreads; jk++) {
        void * currentThread;
        if (pthread_join(threads[jk], & currentThread) != 0) {
            /* undefined reference to a pthread_join*/
        } else {
            printf("main()=>: completed thread[%d]!\n", (int) currentThread);
        }
    }
}

I am having trouble, with creating and join a thread. I am also not sure about the syntax of how to pass a thread parameter by reference. code should print when a thread is created and how long it sleeps in thread routine.

Grice
  • 1,345
  • 11
  • 24
Joe
  • 1
  • 1
  • Do you have a question? – twalberg Oct 23 '14 at 18:03
  • how do I pass thread parameter as a reference instead of by value? also I am getting errors when creating and joining a thread, I don't know if I passed the parameters correctly. – Joe Oct 23 '14 at 18:13

2 Answers2

0

The code you have posted is doing "bad things" with the single argument that pthread_create() allows you to pass to the thread function. pthread_create() allows a single void * to be passed (which can and usually is derived by casting from something else). In your case, you are doing this:

pthread_create(..., (void * ) jj)

This takes the integer value stored in jj, reinterprets it as a void *, and this pointer is what gets passed to your thread function. Strictly speaking, reinterpreting an int as a void * is suspicious at best, but that's the way the PThreads API was designed.

In your thread function, though, you are doing this:

int myThreadNumber = * ((int * ) threadArg);

This takes the void * that you were passed, and reinterprets it as a pointer to int (a.k.a. (int *)), which is generally acceptable on most platforms, but will result in an int * with the value of 0, or 1, ... in your usage. You then attempt to dereference this pointer to get an int, with your * ((int *) ...). On most modern systems, the first iteration of your loop will thus result in a null pointer dereference (although the NULL pointer is not guaranteed to have the numeric value 0, it generally does on most systems/compilers these days), and will probably lead to a program crash as a result, unless you are catching and ignoring the relevant signals, etc.

What you should do in your thread function is cast the void * back to exactly what it was cast from to begin with. In other words, int myThreadNumber = (int) threadArg. Alternatively, you could call pthread_create(.... (void *) &jj) instead, if you really want a pointer to the int so you can pass information back - but that doesn't seem to be what you're trying to do here, and passing a pointer to a stack-based local variable would be a bad thing in other ways.

I'm not sure what you expect regarding being able to pass an argument by reference vs. value. The API states that you must pass a void *, so that's what you must do, unless you want to petition the PThreads folks to change the API... Or write your own...

twalberg
  • 59,951
  • 11
  • 89
  • 84
0

What you are doing in:

  pthread_create( & threads[jj], NULL, threadRoutine, (void * )jj) ;

Is casting the int jj to void*, and passing that value to your threadRoutine(). This is reasonable enough. The problem appears to be that in threadRoutine() you:

  int myThreadNumber = * ((int * ) threadArg);

which is what we call "a mistake". What to should do is:

  int myThreadNumber = (int)threadArg ;

or possibly:

  int myThreadNumber = (intptr_t)threadArg ;

to cast the void* pointer value back to the int it was.

To pass the jj by reference requires something along the lines of:

  int thread_arg[kMaxThreads] ;

  for (int jj = 0; jj < kMaxThreads; jj++) {
    thread_arg[jj] = jj ;
    if (pthread_create( & threads[jj], NULL, threadRoutine, &thread_arg[jj]) != 0) {
        /* undefined reference to a pthread_create*/
    } ...

And then you original

  int myThreadNumber = * ((int * ) threadArg);

can pick up the value.

Of course, the thread is entitled to use the thing pointed at by threadArg at any time while it is running... so you need to make sure it remains valid for that long. In this case the thread_arg[jj] is only used by the 'jj'th thread, and remains in existence until after that thread has beem joined... so all is well.