void *
The designers of pthread_create
did not want to limit the
type of arguments the thread routine can take. So, passing a void
pointer to the thread routine makes it possible to pass any type
of argument. A void pointer can point to any type of variable. One
must be a bit careful when using this kind of pointer though.
It is common practice, but perhaps a bit sloppy to write:
if ( ret = pthread_create(&thread_id[i], NULL, dotprod, (void *) i) )
We interpret i as an address (casting it as a pointer to void). In dotprod we cast back, i_am = (int) arg;. This works on the student system, since pointers (addresses) are stored using four bytes (the same as an int) and because the compiler, gcc,
supports the conversions back and forth. If this is not the case, we
may get problems or at least complaints (as on a 64-bit system).
In older C-versions this was no problem, but in modern C one has to be more careful. Here is a quote from the C-FAQ (Question 4.14):
Pointer-to-integer and integer-to-pointer conversions are
implementation-defined ..., and there is no longer any guarantee that
pointers can be converted to integers and back, without change.
Here are the details for our compiler (i.e. for gcc).
The following may seem like a safer alternative:
int i_tmp;
for(i = 0; i < N_THREADS; i++) {
i_tmp = i; // Not safe to use &i directly
// the cast (void *) &i_tmp is not necessary
if( ret = pthread_create( &thread_id[i], NULL, dotprod, &i_tmp ) ) {
printf ("Error in thread create\n");
exit(1);
}
}
...
In dotprod
// One may not dereference a void pointer, so we convert to a pointer to int first.
i_am = * (int *) arg; // same as *((int *) arg)
This
does not work (on our system), due to a race condition. There is a
delay in starting the threads and the loop will have exited when the i_am-assignments are made. So all threads will likely get i_am = 3 (the last value). It works if we have a pause in each iteration of the loop.
The following version works and does not give any complaints when compiling 32- or 64-bit systems (dotprod as above).
int args[N_THREADS];
...
for(i = 0; i < N_THREADS; i++) {
args[i] = i;
if( ret = pthread_create( &thread_id[i], NULL, dotprod, &args[i] ) ) {
...