我有两种使用蒙特卡罗方法计算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;
}
Run Code Online (Sandbox Code Playgroud)
并有线程:
#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;
}
Run Code Online (Sandbox Code Playgroud)
结果:
$ 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
Run Code Online (Sandbox Code Playgroud)
我的错误在哪里?
R..*_*R.. 11
rand不是线程安全的; 在多个线程中同时使用它将导致未定义的行为.您可以使用在调用时获取并保存互斥锁的函数来包装它rand,或者您可以使用rand_r或(更好)编写一个合适的PRNG来代替它使用.