views:

91

answers:

5

I have a function:

void *findPos(void *param)
{
   int origPos=(int)param;
   ...
}

Which I am calling as a thread runner:

pthread_create( &threadIdArray[i], NULL, findPos, (void *)i );

Now, this way, I get the value of origPos as the typecasted void pointer param, ie. i. This feels like a dirty hack to get around the limitation of being allowed to pass only void pointers to a thread runner function.

Can this be done in a cleaner way?

Edit:

Please note that I run the pthread_create() function in a i for loop, hence passing a pointer to i may not be a safe choice.

+3  A: 

Sure: just supply a pointer to the int, as was the intention of the API designer:

void *findPos(void *param)
{
   int origPos=*(int *)param;
   ...
}

pthread_create( &threadIdArray[i], NULL, findPos, &i );

Casting between int andvoid * is unsafe because the conversion is not necessarily invertible.

You must also ensure that i is still valid when the thread starts executing (if i has automatic storage duration, this would eg be the case if the calling function also calls pthread_join()).

In your case (i being a loop variable), you should duplicating the variable's value in a safe location, eg on the heap via malloc() or by pushing it on a stack with appropriate liefetime:

static int args[THREAD_COUNT];

for(int i = 0; i < THREAD_COUNT; ++i)
{
    args[i] = i;
    pthread_create(&threadIdArray[i], NULL, findPos, args + i);
}
Christoph
+2  A: 

Well, you could pass a pointer to the value, or wrap the value in a struct and pass a pointer to that. The latter isn't cleaner per se, but more expandable if you ever need more than one int worth of parameters to your thread.

UPDATE:
I used to suggest use of use intptr_t from <stdint.h> to express that you intend to cast this integer to/from void *, but reading the documentation a bit more closely (thanks, Christoph) gives:

The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to a pointer to void, and the result will compare equal to the original pointer: intptr_t

This would seem to indicate, just as Christoph said, that you're not safe if you go this route, so don't

unwind
keep in mind that the standard only makes guarantees about the conversion `void *` -> `intptr_t` -> `void *`; `intptr_t` -> `void *` -> `intptr_t` is allowed to change the value (as far as I know)
Christoph
+2  A: 

You should be sure that on your system the value of your parameter has enough room inside a void-pointer (see data type intptr_t). Passing a double value could be problematic with your "direct" method.

I'm often using a parameter structur to pass values to thread (or other) functions.

struct Param {
   double foo;
   int bar;
};  

Param param;
param.foo = 1.0;
param.bar = 1;

pthread_create( &threadIdArray[i], NULL, findPos, &param );
Marco Schmidt
A: 

I don't believe it's a dirty hack really. Wikipedia in its pthreads example does the same.

ecik
no, it doesn't: they convert `int *` -> `void *` (which is safe and the explicit cast actually unnecessary), not `int` -> `void *`
Christoph
+1  A: 

This is a hack that you shouldn't do if you want to have portable code. First the conversion back from void* is not necessarily well defined, as somebody else stated already.

But regardless of that, this is a dirty hack that goes against all possible intentions of the pthread_create API. Simply use something like this:

size_t * threadId = calloc(n, sizeof(size_t));
for (size_t i = 0; i < n; ++i) {
   threadId[i] = i;
   ptread_create(...., &threadId[i]);
}

And you don't have the congestion on i that you would have if you pass the same argument to all the threads.

Jens Gustedt
Great answer, but Christoph beat you to it.
Kedar Soparkar
@crypto: neve mind ;-) but are you sure he did his third edit before I gave my answer ?-) and also I don't like the idea in his to have a `static` array, this supposes that the number of threads is statically known in advance.
Jens Gustedt
@Jens Gustedt, I must've overlooked the "static vs. dynamic no. of threads" part.
Kedar Soparkar