Recursive Fib with Threads, Segmentation Fault?-Collection of common programming errors

I tried to run your code, and came across several surprises:

printf("The number is: %d\n", finalFib);

This line has a small error: %d means printf expects an int, but is passed a long int. On most platforms this is the same, or will have the same behavior anyways, but pedantically speaking (or if you just want to stop the warning from coming up, which is a very noble ideal too), you should use %ld instead, which will expect a long int.

Your fib function, on the other hand, seems non-functional. Testing it on my machine, it doesn’t crash, but it yields 1047, which is not a Fibonacci number. Looking closer, it seems your program is incorrect on several aspects:

void *fib(void *fibToFind)
{
    long retval; // retval is never used

    long newFibToFind = ((long)fibToFind);

    long returnMinusOne; // variable is read but never initialized
    long returnMinustwo; // variable is read but never initialized

    pthread_t minusone; // variable is never used (?)
    pthread_t minustwo; // variable is never used

    if(newFibToFind == 0 || newFibToFind == 1)
        // you miss a cast here (but you really shouldn't do it this way)
        return newFibToFind;        
    else{
        long newFibToFind1 = ((long)fibToFind) - 1; // variable is never used
        long newFibToFind2 = ((long)fibToFind) - 2; // variable is never used
        // reading undefined variables (and missing a cast)
        return returnMinusOne + returnMinustwo;

    }
}

Always take care of compiler warnings: when you get one, usually, you really are doing something fishy.

Maybe you should revise the algorithm a little: right now, all your function does is returning the sum of two undefined values, hence the 1047 I got earlier.

Implementing the Fibonacci suite using a recursive algorithm means you need to call the function again. As others noted, it’s quite an inefficient way of doing it, but it’s easy, so I guess all computer science teachers use it as an example.

The regular recursive algorithm looks like this:

int fibonacci(int iteration)
{
    if (iteration == 0 || iteration == 1)
        return 1;

    return fibonacci(iteration - 1) + fibonacci(iteration - 2);
}

I don’t know to which extent you were supposed to use threads—just run the algorithm on a secondary thread, or create new threads for each call? Let’s assume the first for now, since it’s a lot more straightforward.

Casting integers to pointers and vice-versa is a bad practice because if you try to look at things at a higher level, they should be widely different. Integers do maths, and pointers resolve memory addresses. It happens to work because they’re represented the same way, but really, you shouldn’t do this. Instead, you might notice that the function called to run your new thread accepts a void* argument: we can use it to convey both where the input is, and where the output will be.

So building upon my previous fibonacci function, you could use this code as the thread main routine:

void* fibonacci_offshored(void* pointer)
{
    int* pointer_to_number = pointer;
    int input = *pointer_to_number;
    *pointer_to_number = fibonacci(input);
    return NULL;
}

It expects a pointer to an integer, and takes from it its input, then writes it output there.1 You would then create the thread like that:

int main()
{
    int value = 15;
    pthread_t thread;

    // on input, value should contain the number of iterations;
    // after the end of the function, it will contain the result of
    //  the fibonacci function
    int result = pthread_create(&thread, NULL, fibonacci_offshored, &value);

    // error checking is important! try to crash gracefully at the very least
    if (result != 0)
    {
        perror("pthread_create");
        return 1;
    }

    if (pthread_join(thread, NULL)
    {
        perror("pthread_join");
        return 1;
    }

    // now, value contains the output of the fibonacci function
    // (note that value is an int, so just %d is fine)
    printf("The value is %d\n", value);
    return 0;
}

If you need to call the Fibonacci function from new distinct threads (please note: that’s not what I’d advise, and others seem to agree with me; it will just blow up for a sufficiently large amount of iterations), you’ll first need to merge the fibonacci function with the fibonacci_offshored function. It will considerably bulk it up, because dealing with threads is heavier than dealing with regular functions.

void* threaded_fibonacci(void* pointer)
{
    int* pointer_to_number = pointer;
    int input = *pointer_to_number;

    if (input == 0 || input == 1)
    {
        *pointer_to_number = 1;
        return NULL;
    }

    // we need one argument per thread
    int minus_one_number = input - 1;
    int minus_two_number = input - 2;

    pthread_t minus_one;
    pthread_t minus_two;
    // don't forget to check! especially that in a recursive function where the
    // recursion set actually grows instead of shrinking, you're bound to fail
    // at some point
    if (pthread_create(&minus_one, NULL, threaded_fibonacci, &minus_one_number) != 0)
    {
        perror("pthread_create");
        *pointer_to_number = 0;
        return NULL;
    }
    if (pthread_create(&minus_two, NULL, threaded_fibonacci, &minus_two_number) != 0)
    {
        perror("pthread_create");
        *pointer_to_number = 0;
        return NULL;
    }

    if (pthread_join(minus_one, NULL) != 0)
    {
        perror("pthread_join");
        *pointer_to_number = 0;
        return NULL;
    }

    if (pthread_join(minus_two, NULL) != 0)
    {
        perror("pthread_join");
        *pointer_to_number = 0;
        return NULL;
    }

    *pointer_to_number = minus_one_number + minus_two_number;
    return NULL;
}

Now that you have this bulky function, adjustments to your main function are going to be quite easy: just change the reference to fibonacci_offshored to threaded_fibonacci.

int main()
{
    int value = 15;
    pthread_t thread;

    int result = pthread_create(&thread, NULL, threaded_fibonacci, &value);

    if (result != 0)
    {
        perror("pthread_create");
        return 1;
    }
    pthread_join(thread, NULL);

    printf("The value is %d\n", value);
    return 0;
}

You might have been told that threads speed up parallel processes, but there’s a limit somewhere where it’s more expensive to set up the thread than run its contents. This is a very good example of such a situation: the threaded version of the program runs much, much slower than the non-threaded one.

For educational purposes, this program runs out of threads on my machine when the number of desired iterations is 18, and takes a few seconds to run. By comparison, using an iterative implementation, we never run out of threads, and we have our answer in a matter of milliseconds. It’s also considerably simpler. This would be a great example of how using a better algorithm fixes many problems.

Also, out of curiosity, it would be interesting to see if it crashes on your machine, and where/how.

1. Usually, you should try to avoid to change the meaning of a variable between its value on input and its value after the return of the function. For instance, here, on input, the variable is the number of iterations we want; on output, it’s the result of the function. Those are two very different meanings, and that’s not really a good practice. I didn’t feel like using dynamic allocations to return a value through the void* return value.

Originally posted 2013-11-09 23:21:11.