LINUX.ORG.RU

Синхронизировать цикл внутри openmp секции?

 ,


0

2

Имеется следующая структура программы:

while(true){
	bool cond;
	#pragma omp parallel
	{
		#pragma omp single
		{
			cond = true;
		}
		while(cond){
			int n = omp_get_thread_num();
			do_stuff(n);
			#pragma omp barrier

			#pragma omp single
			{
				sync_stuff();
				cond = is_end();
			}
		}
	}
}
Есть внешний бесконечный цикл, внутри него параллельная секция. В каждом треде необходимо циклически обрабатывать независимый массив данных. Логика такова, что после каждой внутренней итерации запускается некоторый последовательный код, проверяющий, не выполнено ли условие выхода из цикла.

Вопрос: как гарантировать что каждая итерация внутреннего цикла будет запускаться синхронно всеми тредами? В текущей реализации, несмотря на барьер, похоже, что циклы рассинхронизируются и код зависает.

В конечном итоге, нужно просто циклически параллельно запускать do_struff(), а вся эта свистопляска с синхронизацией циклов вылезла из за того, что если написать просто:

while(true){
	bool cond = true;
	while(cond){
		#pragma omp parallel
		{
			int n = omp_get_thread_num();
			do_stuff(n);
		}
		sync_stuff();
		cond = is_end();
	}
}
то, временные затраты на спавн тредов оказываются слишком большими.

★★★★★

Последнее исправление: thunar (всего исправлений: 1)

OpenMP, вроде как, для того и нужно, чтобы делать просто. А если просто с OpenMP не получается, то я бы сделал примерно так: http://stackoverflow.com/questions/19500404/how-to-create-a-thread-pool-using...

И никаких гвоздей.

А так в C++11 достаточно инструментов, чтобы соорудить кроссплатформенный многопоточный велосипед любой степени универсальности.

asaw ★★★★★
()

А если сделать так:

    int num_threads;
    bool volatile cond = true;

#pragma omp parallel
        {
#pragma omp single
            {
            num_threads = omp_get_num_threads();
            }

        while(cond)
            {
#pragma omp for
            for(int i = 0; i < num_threads; ++i)
                do_stuff(i);

#pragma omp single
                {
                sync_stuff();
                cond = is_end();
                }
            }
        }

cdslow ★★
()

Тебе не кажется, что вручную (с pthreads) и одним-единственным мьютексом все было бы гораздо проще?

anonymous
()

Используй блокировку длля синхронизфции.

shkolnick-kun ★★★★★
()
while(true)
{
    bool cond;
    cond = true;
#   pragma omp parallel
    {
        int n = omp_get_thread_num();
        while(cond)
        {
            do_stuff(n);
#           pragma omp master
            {
                sync_stuff();
                cond = is_end();
            }
        }
    }
}

Так не пробовал?

shkolnick-kun ★★★★★
()
Последнее исправление: shkolnick-kun (всего исправлений: 1)
Ответ на: комментарий от shkolnick-kun
while(true)
{
    bool cond;
    cond = true;
#   pragma omp parallel
    {
        int n = omp_get_thread_num();
        while(cond)
        {
#           pragma omp barrier
            do_stuff(n);
#           pragma omp master
            {
                sync_stuff();
                cond = is_end();
            }
        }
    }
}

Или так... Раз уж тебе надо, чтобы иттерации были синхронизированы...

shkolnick-kun ★★★★★
()

блин, походу таки я где-то внутри программы напортачил с доступом к общим ресурсам, отсюда и тормоза. сейчас сделал в чистом виде тестовую болванку — и всё норм:

calculating in pthreads (8 threads): 1000: 15s.
calculating in OpenMP (8 threads): 1000: 14s.
calculating in serial: 1000: 111s.
#include <iostream>
#include <iomanip>  
#include <thread>
#include <omp.h>
#include <mutex>
#include <cmath>

using namespace std;
std::mutex _mutex;

float** xss;
const int points =100000;
const int loops = 1000;

int func(int n){
	auto& xs = xss[n];
	for(int i=0; i<points; i++){
		auto& x = xs[i];
		xs[i] = sin(x) * cos(x) - x + sqrt(abs(x));
	}
  return 0;
}

int main ()
{
	const int threads_n = std::thread::hardware_concurrency();
	xss = new float* [threads_n];
	for(int n = 0; n<threads_n; n++){
		xss[n] = new float [points];
		for(int i = 0; i<points; i++){
			xss[n][i] = rand();
		}
	}
	std::thread threads[threads_n];

	while(1){
		{ //pthreads code
			const time_t t_start = std::time(NULL);
			for(int t=0; t<loops+1; t++){
				std::cout<<"\rcalculating in pthreads ("
					<<threads_n<<" threads): "<<setfill('0')<<setw(4)<<t;
				std::cout.flush();
				for (int n = 0; n < threads_n; n++){
					threads[n] = std::thread(func, n);
				}
				for (int n = 0; n < threads_n; n++){
					threads[n].join();
				}
			}
			const time_t t_end = std::time(NULL);
			std::cout << ": " << t_end-t_start << "s." << std::endl;
		}

		{ //openmp code
			omp_set_dynamic(0);
			omp_set_num_threads(threads_n);
			const time_t t_start = std::time(NULL);
			for(int t=0; t<loops+1; t++){
				std::cout<<"\rcalculating in OpenMP: "<<setfill('0')<<setw(4)<<t;
				std::cout.flush();
				#pragma omp parallel for schedule(static)
				for (int n = 0; n < threads_n; n++){
					func(n);
				}
			}
			const time_t t_end = std::time(NULL);
			std::cout << ": " << t_end-t_start << "s." << std::endl;
		}

		{ //serial code
			const time_t t_start = std::time(NULL);
			for(int t=0; t<loops+1; t++){
				std::cout<<"\rcalculating in serial: "<<setfill('0')<<setw(4)<<t;
				std::cout.flush();
				for (int n = 0; n < threads_n; n++){
					func(n);
				}
			}
			const time_t t_end = std::time(NULL);
			std::cout << ": " << t_end-t_start << "s." << std::endl;
		}
	}

}

thunar ★★★★★
() автор топика
Последнее исправление: thunar (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.