计算线程中的 Pi
我有两种使用 蒙特卡罗方法 计算 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
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 callingrand
, or you can userand_r
or (better yet) write a decent PRNG to use in its place.除了其他答案之外,在下面的代码中,
a 是共享的,但不受互斥体保护,导致错误的添加。虽然您可能没有遇到过这个问题,但您最终会遇到。
Besides the other answers, in the following code
a is shared but not guarded by mutex, resulting in wrong addition. Though you may have not encountered this problem, but you will eventually.
您的
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.