Question

I've been reading and learning about POSIX threads, and tried to write some simple codes to understand it better.

#include <stdio.h> /* standard I/O routines */
#include <pthread.h> /* pthread functions and data structures */

/* function to be executed by the new thread */
void* PrintHello(void* data)
{
    pthread_t tid = (pthread_t)data;
    printf("Hello from new thread  %d - got %d\n", pthread_self(), tid);
    pthread_exit(NULL); /* terminate the thread */
}

int main(int argc, char* argv[])
{
    int rc; /* return value */
    pthread_t thread_id;
    int  tid;   

    thread_id = pthread_self();
    printf("FLAG = %d ", thread_id);

    /* create a new thread that will execute 'PrintHello' */
    rc = pthread_create(&thread_id, NULL, PrintHello, (void*)thread_id);
    if(rc) /* could not create thread */
    {
        printf("\n ERROR: return code from pthread_create is %u \n", rc);
    exit(1);
    }
    printf("\n   Created new thread (%d) ... \n",  thread_id);
    pthread_exit(NULL); /* terminate the thread */
}

For this code I get the following output:

FLAG = 363480832 
   Created new thread (355198720) ... 
Hello from new thread  355198720 - got 363480832

What is bothering me is why thread_id which is 363480832, becomes 355198720, same as thread_id of a function that was called from main (PrintHello()). I assumed that thread id doesn't change throughout the program execution. Or is it something inside the function that changes it?

Was it helpful?

Solution

If you're doing anything with a pthread_t other than passing it to a function that takes one, you're doing something wrong. Only the pthreads API knows how to use a pthread_t correctly. They can have any internal structure that's convenient for the implementation.

Being a C language construct, pthread_t behaves more like char *. The necessary language constructs to make it behave like std::string don't exist. So you have to treat it like char *.

A char * contains a string somehow, but you have to understand its implementation to get that value out. Consider:

char *j = "hello";
char *k = strdup (j);
if (j == k)
   printf ("This won't happen\n");
printf ("%d\n", j);
printf ("%d\n", k); // these won't be equal

You can't compare char *'s with == to see if they refer to the same string. And if you print out j and k, you'll get different values.

Similarly, a pthread_t refers to one particular thread somehow. But you have to understand how to get the value out. Two pthread_ts can have different apparent values but still refer to the same thread just as two char *s can have different apparent values but still refer to the same string.

Just as you compare two char *'s with strcmp if you want to tell if they refer to the same string value, you compare two pthread_ts with pthread_equal to tell if they refer to the same thread.

So this line of code makes no sense:

printf("FLAG = %d ", thread_id);

A pthread_t is not an integer and you can't print it with a %d format specifier. POSIX has no printable thread IDs. If you want one, you need to code one (perhaps using pthread_getspecific).

OTHER TIPS

In C, arguments are passed by value. In particular, the argument (void *)thread_id is an expression that's evaluated before calling pthread_create, so the fact that pthread_create writes to thread_id as a result of &thread_id being passed as the first argument is irrelevant. If you were instead passing &thread_id rather than (void *)thread_id as the argument to the new thread start function, and dereferencing it there, then you may see the effects you want; however, it's not clear to me that pthread_create's writing of the new thread id via its first argument is required to take place before the new thread starts, so there is probably a data race if you do it that way.

Further, note that David's answer is also correct. It's invalid to print thread ids this way since they are formally an opaque type.

In this line:

rc = pthread_create(&thread_id, NULL, PrintHello, (void*)thread_id);

as the manual says, pthread_create() shall store the ID of the created thread in the location referenced by thread_id. In this example, it would be modified to 355198720, which is the tid of new thread PrintHello().

Besides, it may be better to change the argument for PrintHello to:

rc = pthread_create(&thread_id, NULL, PrintHello, (void*)&thread_id);

and in PrintHello(), it would be:

void* PrintHello(void* data)
{
    pthread_t tid = (pthread_t)(*data);
    ...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top