Openmp无法自动创建线程

时间:2013-06-19 19:40:23

标签: c++ multithreading openmp

我正在尝试学习如何使用openmp进行多线程处理。 这是我的代码:

#include <iostream>
#include <math.h>
#include <omp.h>
//#include <time.h>
//#include <cstdlib>

using namespace std;

bool isprime(long long num);

int main()
{
        cout << "There are " << omp_get_num_procs() << " cores." << endl;
        cout << 2 << endl;
        //clock_t start = clock();
        //clock_t current = start;
        #pragma omp parallel num_threads(6)
        {
        #pragma omp for schedule(dynamic, 1000)
        for(long long i = 3LL; i <= 1000000000000; i = i + 2LL)
        {
                /*if((current - start)/CLOCKS_PER_SEC > 60)
                {
                        exit(0);
                }*/
                if(isprime(i))
                {
                        cout << i << " Thread: " << omp_get_thread_num() << endl;
                }
        }
        }
}

bool isprime(long long num)
{
        if(num == 1)
        {
                return 0;
        }
        for(long long i = 2LL; i <= sqrt(num); i++)
        {
                if (num % i == 0)
                {
                        return 0;
                }
        }
        return 1;
}

问题在于我希望openmp根据可用的核心数自动创建多个线程。如果我取出num_threads(6),那么它只使用1个线程,而omp_get_num_procs()正确输出64个。

如何让它发挥作用?

4 个答案:

答案 0 :(得分:1)

您忽略了提到您正在使用的编译器和OpenMP实现。我会猜测你正在使用其中一个,比如PGI,它不会自动假设在默认并行区域中创建的线程数,除非要求这样做。由于您没有指定编译器,我不能确定这些选项实际上会对您有所帮助,但对于PGI的编译器,在编译和链接可执行文件时,必要的选项是-mp=allcores。添加后,它将导致系统为并行区域为每个核心创建一个线程,这些并行区域不指定线程数或设置适当的环境变量。

默认情况下,使用从omp_get_num_procs获取的数字来设置线程数的限制,但不一定是创建的数量。如果要动态设置创建的数字,请在运行应用程序之前将环境变量OMP_NUM_THREADS设置为所需的数字,它应该按预期运行。

答案 1 :(得分:0)

我不确定我是否理解你的问题,但似乎你几乎就在那里。你的意思是:

#include <omp.h>
#include <iostream>

int main(){

    const int num_procs = omp_get_num_procs();
    std::cout<<num_procs;

#pragma omp parallel for num_threads(num_procs) default(none)
    for(int i=0; i<(int)1E20; ++i){
    }

    return 0;

}

答案 2 :(得分:0)

除非我错误地认为错误,否则OpenMP通常会将I / O序列化(至少是单个流),这可能至少是问题出现的部分原因。将其从循环中删除,并按摩其余部分(在并行化工作中没有太大意义,直到你有相当高效的串行代码),我最终会得到这样的结果:

#include <iostream>
#include <math.h>
#include <omp.h>

using namespace std;

bool isprime(long long num);

int main()
{
    unsigned long long total = 0;

    cout << "There are " << omp_get_num_procs() << " cores.\n";

    #pragma omp parallel for reduction(+:total)
    for(long long i = 3LL; i < 100000000; i += 2LL)
        if(isprime(i))
            total += i;

    cout << "Total: " << total << "\n";
}

bool isprime(long long num) {
    if (num == 2)
        return 1;
    if(num == 1 || num % 2 == 0)
        return 0;
    unsigned long long limit = sqrt(num);

    for(long long i = 3LL; i <= limit; i+=2)
        if (num % i == 0)
            return 0;
    return 1;
}

这不打印出线程编号,但计时我得到这样的东西:

Real    78.0686
User    489.781
Sys     0.125

请注意&#34;用户&#34;时间超过&#34; Real&#34;时间,表示负载分布在该机器上可用的核心8上,效率约为80%。通过更多工作,您可以进一步改进,但即使使用这个简单版本,我们也会看到使用的核心不止一个(在64核机器上,我们应该看到至少50个:比单线程代码有1个改进,可能比这更好一些。)

答案 3 :(得分:0)

我看到你的代码唯一的问题是当你输出时你需要把它放在critcal部分,否则多个线程可以同时写入同一行。
请参阅我的代码更正。

就一个帖子而言,我认为您可能会看到的是使用dynamic。运行小数字的线程比运行大数字的线程快得多。当小数字的线程完成并获得另一个小数字列表运行时,它会快速完成,而大数字的线程仍在运行。这并不意味着你只运行一个线程。在我的输出中,我看到相同线程的长流,找到素数,但最终其他人报告。您还将卡盘大小设置为1000,因此,如果您仅运行超过1000个数字,则循环中将只使用一个线程。

在我看来,你正试图找到一个素数列表或素数的总和。你正在使用试验部门。这比使用“Eratosthenes的筛子”效率低得多。

以下是Eratosthenes的筛选示例,它使用OpenMP在我的4核心系统上在不到一秒的时间内找到了前十亿个数字中的素数。 http://create.stephan-brumme.com/eratosthenes/

我稍微清理了你的代码,但没有尝试优化任何东西,因为算法效率很低。

int main() {
    //long long int n = 1000000000000;
    long long int n = 1000000;
    cout << "There are " << omp_get_num_procs() << " cores." << endl;
    double dtime = omp_get_wtime();
    #pragma omp parallel
    {
        #pragma omp for schedule(dynamic)
        for(long long i = 3LL; i <= n; i = i + 2LL) {
            if(isprime(i)) {
                #pragma omp critical 
                {
                    cout << i << "\tThread: " << omp_get_thread_num() << endl;
                }
            }
        }
    }
    dtime = omp_get_wtime() - dtime;
    cout << "time " << dtime << endl;
}