I am working on the following function. This function should create n threads. Also it should print the tid of the child thread. But at the moment I am little bit confused. When I execute it and for example I create 5 threads, it returns all the time the same tid. As far as I understood the tid is the thread Id of the caller. Does the same caller call all these threads or did I something wrong. Here's the code:
void spawnThreads( unsigned int n) {
int threads = n, ret = -1;
pthread_t * thread = malloc(sizeof(pthread_t)*threads);
pid_t tid;
int i;
for(i = 0; i < threads; i++) {
ret = pthread_creation(&thread[i], NULL, (void *(*)(void *)) foo, NULL); // foo does not do anything
if( ret != 0) {
printf("pthread error!\n");
}
tid = syscall(SYS_gettid);
printf("%d %d\n", i, tid);
printf("I just created thread %d\n", i);
pthread_join(thread[i],NULL);
}
void * foo(void) {
return NULL;
}
For example, I get the for the following input spawnThreads(4) the following output:
0 2411
I just created thread 0
1 2411
I just created thread 1
2 2411
I just created thread 2
3 2411
I just created thread 3
To sum up, the function should print >i< >tid<. >tid< denotes the TID of the child and >i< runs from 1 to n.
But why do I get four times the same tid? What did I do wrong? I would appreciate it, if someone could explain me what went wrong.
The reason you're getting the same TID for each thread is that you're calling syscall(SYS_gettid)
from the main thread each time, rather than from within the new thread you create. You need to call it from inside your thread function and then provide a way to pass the information back to the main thread if it's needed there.
As an example of one way to do it (some error checking omitted):
Create a struct to hold a mutex, condition, the TID, and a flag to indicate when the TID is valid.
struct s_threadId {
pthread_mutex_t mtx; /* mutex & condition to allow main thread to
wait for the new thread to set its TID */
pthread_cond_t cond; /* '' */
pid_t id; /* to hold new thread's TID */
int ready; /* to indicate when 'id' is valid, in case
the condition wait gets interrupted */
};
Then change your thread function to lock, set, and signal (and move it so that it's declaration is visible before spawnThreads()
):
void *foo(void *arg)
{
struct s_threadId *thId = arg;
/* Lock mutex... */
pthread_mutex_lock(&thId->mtx);
/* Get and save TID and ready flag.. */
thId->id = syscall(SYS_gettid);
thId->ready = 1;
/* ..and signal main thread that we're ready */
pthread_cond_signal(&thId->cond);
/* ..then unlock when we're done. */
pthread_mutex_unlock(&thId->mtx);
/* ... */
return NULL;
}
...and modify your spawnThreads
function to initialize/cleanup the struct members and get the TID once the thread sets it:
void spawnThreads(unsigned int n)
{
pthread_t thread; /* reused for each thread, since they run 1 at a time */
/* struct to pass back TID */
struct s_threadId threadId;
pthread_cond_init(&threadId.cond, NULL); /* init condition */
pthread_mutex_init(&threadId.mtx, NULL); /* init mutex */
int i;
for (i = 0; i < n; i++) {
/* lock mutex *before* creating the thread, to make the new thread
wait until we're ready before signaling us */
pthread_mutex_lock(&threadId.mtx);
/* clear ready flag before creating each thread */
threadId.ready = 0;
/* create threads and pass address of struct as argument */
if (pthread_create(&thread, NULL, foo, &threadId)) {
printf("pthread error!\n");
} else {
/* Wait on the condition until the ready flag is set */
while (!threadId.ready) {
pthread_cond_wait(&threadId.cond, &threadId.mtx);
}
/* Now we have the TID... */
printf("%d %d\n", i, threadId.id);
printf("I just created thread %d\n", i);
}
/* ..and unlock the mutex when done. */
pthread_mutex_unlock(&threadId.mtx);
pthread_join(thread, NULL);
}
/* When we're completely done with the struct we need to clean up the
mutex and condition variable */
pthread_mutex_destroy(&threadId.mtx);
pthread_cond_destroy(&threadId.cond);
}
In the above, the mutex and condition wait are needed to make sure that the main thread doesn't try to print the TID until the new thread has had a chance to set it. The main thread starts the new one and then waits, and the new thread signal when it's done storing the TID so the main thread can continue.