2017-10-16 113 views
1

下面的代码执行与1个螺纹比具有更好的慢2(使用4个线程给出加快,虽然):OpenMP中使用rand_r“为”是具有2个线程

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

int main(int argc, char **argv) { 
    int n = atoi(argv[1]); 
    int num_threads = atoi(argv[2]); 
    omp_set_num_threads(num_threads); 

    unsigned int *seeds = malloc(num_threads * sizeof(unsigned int)); 
    for (int i = 0; i < num_threads; ++i) { 
    seeds[i] = 42 + i; 
    } 

    unsigned long long sum = 0; 
    double begin_time = omp_get_wtime(); 
    #pragma omp parallel 
    { 
    unsigned int *seedp = &seeds[omp_get_thread_num()]; 
    #pragma omp for reduction(+ : sum) 
    for (int i = 0; i < n; ++i) { 
     sum += rand_r(seedp); 
    } 
    } 
    double end_time = omp_get_wtime(); 

    printf("%fs\n", end_time - begin_time); 
    free(seeds); 
    return EXIT_SUCCESS; 
} 

在我的笔记本电脑(2芯,支持HT)我得到以下结果:

$ gcc -fopenmp test.c && ./a.out 100000000 1 
0.821497s 
$ gcc -fopenmp test.c && ./a.out 100000000 2 
1.096394s 
$ gcc -fopenmp test.c && ./a.out 100000000 3 
0.933494s 
$ gcc -fopenmp test.c && ./a.out 100000000 4 
0.748038s 

的问题仍然存在,而不减少,drand48_r带来了没有什么区别,动态调度使事情变得更糟。但是,如果我用没有连接随机的东西替换循环体,即一切正常,按预期工作。

回答

3

这是错误分享的教科书示例。通过使用每个线程占用一个元素的种子数组,您可以强制逻辑上的私有变量在物理上位于内存中彼此相邻的位置。因此,这些都在同一个缓存行中。这意味着虽然没有线程试图修改其他线程的种子,但是每次线程在每次迭代时都会修改缓存线本身。实际的麻烦在于系统无法检测变量对缓存一致性的修改,只能缓存行修改。因此,在每个线程的每次迭代中,高速缓存线已被另一个线程修改,并且从系统的角度来看不再有效。它必须从内存中重新加载(很可能来自共享的三级缓存),这会导致代码变慢。

试试这一个,而不是(未测试):

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

int main(int argc, char **argv) { 
    int n = atoi(argv[1]); 
    int num_threads = atoi(argv[2]); 
    omp_set_num_threads(num_threads); 

    unsigned long long sum = 0; 
    double begin_time = omp_get_wtime(); 
    #pragma omp parallel 
    { 
    unsigned int seed = 42 + omp_get_thread_num(); 
    #pragma omp for reduction(+ : sum) 
    for (int i = 0; i < n; ++i) { 
     sum += rand_r(&seed); 
    } 
    } 
    double end_time = omp_get_wtime(); 

    printf("%fs\n", end_time - begin_time); 
    return EXIT_SUCCESS; 
} 
+0

啊!我省略了rand_r实际上修改了给定的参数。好答案 :) – Harald