I originally had a global variable for my fibonacci variable array, but found out that is not allowed. I need to do elementary multithreading and handle race conditions, but I can't get past feeding an int as a void argument in pthread create. I've tried using a constant pointer with no luck. For some strange reason the void* gets past the first boolean test but not the else if:
$ gcc -o fibonacci fibonacci.c
fibonacci.c:22:16: warning: comparison between pointer and integer ('void *' and 'int')
else if (arg == 1)
~~~ ^ ~
1 warning generated.
My code is a mess and I am getting really confused because I have rewritten it so many times. If I cast all the args in my thread run function as ints I get a segmentation fault 11, which makes sense. All attempts at passing the i index by address and dereferencing it have failed, as it is a void and can't be used as an int. Can you suggest something else?
#include<stdio.h> //for printf
#include<stdlib.h> //for malloc
#include<pthread.h> //for threading
#define SIZE 25 //number of fibonaccis to be computed
int *fibResults; //array to store fibonacci results
void *run(void *arg) //executes and exits each thread
{
if (arg == 0)
{
fibResults[(int)arg] = 0;
printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);
pthread_exit(0);
}
else if (arg == 1)
{
fibResults[(int)arg] = 1;
printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);
pthread_exit(0);
}
else
{
fibResults[(int)arg] = fibResults[(int)arg -1] + fibResults[(int)arg -2];
printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);
pthread_exit(0);
}
}
//main function that drives the program.
int main()
{
pthread_attr_t a;
fibResults = (int*)malloc (SIZE * sizeof(int));
pthread_attr_init(&a);
for (int i = 0; i < SIZE; i++)
{
pthread_t thread;
pthread_create(&thread, &a, run,(void*) &i);
printf("Thread[%d] created\t", i);
fflush(stdout);
pthread_join(thread, NULL);
printf("Thread[%d] joined & exited\t", i);
}
return 0;
}
You don't need the cast in the call to
pthread_create()
— the conversion tovoid *
is automatic.In the thread function, you could use
However, you've now got a synchronization problem; all the threads are using the same (pointer to the same) integer variable, and you can't predict which value they're going to see because of scheduling issues. The per-thread data needs to be 'per thread'.
So, there are various ways around that. In this context, I'd probably use
and in
main()
:and then in the thread function:
Now the casts — the double cast even — is necessary. The cast to
uintptr_t
ensures the integer value is big enough to hold a pointer; the cast tovoid *
is needed because there isn't an implicit cast from any integer type tovoid *
. This ensures each thread function invocation has a different value. Sharing a pointer to anint
means that everything is uncontrolled.In the
run()
function you should do:and in rest of the
run()
, you don't need to cast thearg
. Replace(int)arg
witharg
.EDIT:
The way you are passing the argument to
fun()
while creating threads may cause race condition because all threads will be using same pointer. Check the @Jonathan's answer to avoid this problem.@efuddy. Instead of
(int)arg
you should use(int *)arg
to properly cast the **void pointer*void *arg