计算线程中的 Pi

发布于 2024-11-14 12:24:02 字数 1980 浏览 3 评论 0原文

我有两种使用 蒙特卡罗方法 计算 pi 的实现:带线程和不带线程。没有线程的实现工作得很好,但是有线程的方法在准确性和性能方面存在问题。这是代码:

没有线程:

#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;
}

和有线程:

#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;
}

结果:

$ 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

我的错误在哪里?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜巴黎 2024-11-21 12:24:02

rand 不是线程安全的;在多个线程中同时使用它会导致未定义的行为。您可以用一个函数包装它,该函数在调用 rand 时获取并保存互斥体,或者您可以使用 rand_r 或(更好)编写一个像样的 PRNG 以在其中使用地方。

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.

南七夏 2024-11-21 12:24:02

除了其他答案之外,在下面的代码中,

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

a 是共享的,但不受互斥体保护,导致错误的添加。虽然您可能没有遇到过这个问题,但您最终会遇到。

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.

っ左 2024-11-21 12:24:02

您的 rand() 在线程中并发将产生相同的数字序列,因为您得到其他结果,但算法很好是概率< /strong>,没有任何保证)。为什么顺序一样?因为种子 rand 实例是每个进程的,所以线程是进程,但是轻量级的。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文