Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counting Pi in threads

Tags:

c

pi

pthreads

I have two implementations of counting pi with Monte-Carlo method: with and without threads. Implementation without threads working just fine, but method with threads have problems with accuracy and perfomance. Here is code:

Without threads:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int main()
{
    srand(time(NULL));

    unsigned long N = 0, Nin = 0;
    float x,y;

    while(N < 2E+9)
    {
        x = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;
        y = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;

        if(x*x + y*y < 25.0) Nin += 1;
        N++;
    }
    long double pi = 4.0 * (long double)Nin / (long double)N;

    printf("\tPi1: %.20Lf\n\t%lu %lu\n", pi, Nin, N);

    return 0;
}

And with threads:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>


typedef struct 
{
    unsigned long Nin;
    unsigned long N;
} nums;


void pi_counter(nums* a)
{
    float x,y;
    unsigned int N = 0, Nin = 0;

    while(N < 1E+9)
    {
        x = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;
        y = rand()/((float)RAND_MAX + 1.0)*10.0 - 5.0;


        if(x*x + y*y < 25.0) Nin++;
        N++;
    }

    a -> Nin += Nin;
    a -> N   += N;
}


int main()
{
    pthread_t thread1, thread2, thread3;
    nums a;

    srand(time(NULL));

    pthread_create( &thread1, NULL, pi_counter, &a );
    pthread_create( &thread2, NULL, pi_counter, &a );

    pthread_join( thread1, NULL );
    pthread_join( thread2, NULL ); 

    long double pi = 4.0 * (long double)a.Nin / (long double)a.N;


    printf("\tPi2: %.20Lf\n\t%lu %lu\n", pi, a.Nin, a.N);

    return 0;
}

Results:

$ time ./pi2
    Pi2: 3.14147154999999999995
    1570735775 2000000000

real    1m1.927s
user    1m23.624s
sys 0m0.139s



$ time ./pi
    Pi1: 3.14158868600000000006
    1570794343 2000000000

real    0m49.956s
user    0m49.887s
sys 0m0.022s

Where is my mistake?

like image 958
sashab Avatar asked Jun 05 '11 22:06

sashab


3 Answers

rand is not thread-safe; simultaneously using it in multiple threads will result in undefined behavior. You can either wrap it with a function that acquires and holds a mutex while calling rand, or you can use rand_r or (better yet) write a decent PRNG to use in its place.

like image 68
R.. GitHub STOP HELPING ICE Avatar answered Nov 15 '22 23:11

R.. GitHub STOP HELPING ICE


Besides the other answers, in the following code

a -> Nin += Nin;
a -> N   += N;

a is shared but not guarded by mutex, resulting in wrong addition. Though you may have not encountered this problem, but you will eventually.

like image 2
Chang Peng Avatar answered Nov 15 '22 23:11

Chang Peng


Your rand() concurrently in threads will result same numbers sequence, because you get other results but algorithm is fine (is probabilistic, nothing is guaranteed). Why same sequence? Because seed rand instance is per process, thread is process to but lightweight.

like image 1
Svisstack Avatar answered Nov 15 '22 23:11

Svisstack