首页 > 解决方案 > OpenMP 输出不正确的答案

问题描述

我输入了这个简单的代码来计算 2 到 5,000,000 之间的素数个数。该算法工作正常,它输出正确的答案,但是当我尝试使用 OpenMP 来加速执行时,它每次都会输出不同的答案。

#include "time.h"
#include "stdio.h"
#include "omp.h"
int main()
{
    clock_t start = clock();
    int count = 1;
    int x;
    bool flag;
    #pragma omp parallel for schedule(static,1) num_threads(2) shared(count) private(x,flag)
    for (x = 3; x <= 5000000; x+=2)
    {
        flag = false;
        if (x == 2 || x == 3)
            count++;
        else if (x % 2 == 0 || x % 3 == 0)
            continue;
        else
        {
            for (int i = 5; i * i <= x; i += 6)
            {
                if (x % i == 0 || x % (i + 2) == 0)
                {
                    flag = true;
                    break;
                }
            }
            if (!flag)
                count++;
        }
    }
    clock_t end = clock();
    printf("The execution took %f ms\n", (double)end - start / CLOCKS_PER_SEC);
    printf("%d\n", count);
}

该代码不适用于任何数量的线程、动态或静态调度或不同的块大小。我试过弄乱私有和共享变量,但它仍然不起作用,并且在 for 循环中声明 x 和 flag 也不起作用。我正在使用 Visual Studio 2019,并且启用了 OpenMP 支持。我的代码有什么问题?

标签: cmultithreadingparallel-processingopenmp

解决方案


您的count变量存在竞争条件,多个线程可以尝试同时更新它。简单的解决方法是使用 OpenMPreduction()子句为每个线程提供变量的私有副本,并让它们全部正确添加:

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

int main(void)
{
    clock_t start = clock();
    int count = 1;
#pragma omp parallel for schedule(static,1) num_threads(2) reduction(+:count)
    for (int x = 3; x <= 5000000; x+=2)
    {
        bool flag = false;
        if (x == 2 || x == 3)
            count++;
        else if (x % 2 == 0 || x % 3 == 0)
            continue;
        else
        {
            for (int i = 5; i * i <= x; i += 6)
            {
                if (x % i == 0 || x % (i + 2) == 0)
                {
                    flag = true;
                    break;
                }
            }
            if (!flag)
                count++;
        }
    }
    clock_t end = clock();
    printf("The execution took %f ms\n", (double)end - start / CLOCKS_PER_SEC);
    printf("%d\n", count);
}

这将输出 348513(通过其他软件验证为正确的数字)。


还要注意清理标题并移动一些变量声明以避免需要private()子句。

您也可以创建count一个原子 int,但这比reduction()在我的测试中使用要慢。


推荐阅读