PDA

View Full Version : strange behavior of pthread_create



np2k
05-10-2010, 12:24 PM
Hi all. I'm new to this forum.
I've some problem with this piece of code:



#define N 2
void* handler_function(void* args) {
int index = *((int*)args);
printf("\n-----index = %d------\n",index);
return NULL;
}

int main() {
pthread_t threads[N*N];
int i;
for (i=0;i<N*N;i++)
pthread_create(&(threads[i]),NULL,&handler_function,&i);

for (i=0;i<N*N;i++)
pthread_join(threads[i],NULL);
}


try to compile&exec it (i use posix thread so add -lpthread option to gcc command)

my output:


np2k@serena:~/source/thread$ gcc -o test test.c -lpthread
np2k@serena:~/source/thread$ ./test
-----index = 2------
-----index = 2------
-----index = 0------
-----index = 0------
np2k@serena:~/source/thread$


the problem is with pthread_create function. in fact, when I print the index value in the thread_function routine, I don't see all the values of index (from 0 to N*N-1).
A tricky solution to this matter is to add a sleep(1) after pthread_create. By doing so, things work well. But I don't want to wait, obviously.

please help me :)

brewbuck
05-10-2010, 12:43 PM
Each thread gets the same pointer to the argument. As the loop continues, this value keeps changing out from underneath the threads.

np2k
05-10-2010, 12:51 PM
As the loop continues, this value keeps changing out from underneath the threads.

i don't understand...and, anyway, what could be a solution to this problem?

brewbuck
05-10-2010, 01:02 PM
What good is a solution when you don't understand the problem?

np2k
05-10-2010, 01:09 PM
What good is a solution when you don't understand the problem?

ok, let me understand please

Salem
05-10-2010, 01:40 PM
> what could be a solution to this problem?
6 months of background reading, research and studying.

Here's why you shouldn't (or shouldn't yet).
Threads Considered Harmful (http://c2.com/cgi/wiki?ThreadsConsideredHarmful)

If debugging a normal application (single thread) can be scaled from 1 to 10, then making it threaded easily pushes it into the hundreds.
If you end up with a race condition that only shows up under heavy load, then any attempt to debug it will cause the problem to go away. At that point, you're basically screwed.

This tutorial seems pretty good
https://computing.llnl.gov/tutorials/pthreads/

Make no mistake, threads are a chainsaw tool. You need to be exceedingly careful about how you use it. For starters, you need a damn good plan as to what each thread is doing, what data it might be sharing and how it synchronises with the rest of the system.
You CANNOT just hack a thread program together and hope it will work.

np2k
05-10-2010, 04:33 PM
yes, salem. thanks for your links...but i've studied the threads and the program that i've post has a strange behavior: i don't have understand why.

Codeplug
05-10-2010, 05:15 PM
>> pthread_create(&(threads[i]),NULL,&handler_function,&i);
You are passing in the address of the variable "i". So all threads are reading i's value - which is being changed by the for-loop's "i++".

Just pass in a copy of i's value:
> pthread_create(&(threads[i]),NULL,&handler_function,(void*)i);

Then:
> int index = (int)args;

gg

MK27
05-10-2010, 07:21 PM
> what could be a solution to this problem?
6 months of background reading, research and studying.

A lot of obfuscation and mystification of thread apparatus around. Going by some of the documentation, you would think learning to use a fairly basic technology is equivalent to being an Apollo astronaut. Then all of a sudden your VCR is working fine and you wonder what the beejesus all the fuss was about.

Anyway, I don't use threads that much :p but as Codeplug indicates, you are are assuming something about when that thread is executing and what the value of i is at that point:


for (i=0;i<N*N;i++)
pthread_create(&(threads[i]),NULL,&handler_function,&i);

for (i=0;i<N*N;i++) /* OMG!!! */
pthread_join(threads[i],NULL);


Hopefully that wasn't too hard to explain.

Salem
05-10-2010, 10:33 PM
Like brewbuck said, if you don't understand that &i gives shared access to a volatile location, then you're simply not ready for the rest of the dragons that lurk in the dark corners of the pthread dungeons.

np2k
05-11-2010, 02:22 AM
>> pthread_create(&(threads[i]),NULL,&handler_function,&i);
You are passing in the address of the variable "i". So all threads are reading i's value - which is being changed by the for-loop's "i++".

damn it! I had missed a "silly" detail...

but, wait...what a dirty thing! in this way, in thread_function routine I get the value of the args pointer's address which coincides with the value of i
isn't it?

@Salem...I know what &i gives...and even if this were so, you could not explain things well? thanks salem.......

Salem
05-11-2010, 10:07 AM
brewbuck in post #2 told you exactly what the problem was, and in post #3 you were all "huh?"

And now you get it!?

MK27
05-11-2010, 11:05 AM
And now you get it!?

@Salem: Perhaps because it has been too many years since you had to deal with this "confusion" it is hard for you to recognize what might "clarify"?

This is not to say that brewbuck did not explain "exactly what the problem was", just to raise the question of for whom.



but, wait...what a dirty thing! in this way, in thread_function routine I get the value of the args pointer's address which coincides with the value of i
isn't it?

The address of a variable does not coincide with it's value. Passing a value is not the same as passing the address of a value. Of course, in single threaded programming the value of a variable passed by reference will not change during a function's execution. But with parallel processing, it can. Without a lock, it could even change during a read, which means all variables that are accessed by more than one thread should use a locking mechanism of some sort (such as a mutex) to ensure it is only accessed by one thread at a time.

However, if you passed the value of i instead of it's address, then it would be a separate local stack value inside each instance of handler_function, so that would not be an issue.

np2k
05-12-2010, 02:48 AM
@Salem: Perhaps because it has been too many years since you had to deal with this "confusion" it is hard for you to recognize what might "clarify"?

This is not to say that brewbuck did not explain "exactly what the problem was", just to raise the question of for whom.


thanks...


The address of a variable does not coincide with it's value. Passing a value is not the same as passing the address of a value. Of course, in single threaded programming the value of a variable passed by reference will not change during a function's execution. But with parallel processing, it can. Without a lock, it could even change during a read, which means all variables that are accessed by more than one thread should use a locking mechanism of some sort (such as a mutex) to ensure it is only accessed by one thread at a time.
However, if you passed the value of i instead of it's address, then it would be a separate local stack value inside each instance of handler_function, so that would not be an issue.

sorry but I have not explained well, i'm italian and my english is not good. all of your speech was clear, from long time...I said something else, but now it's no important because I clarified the question by myself. anyway thank you for your help!