2015-11-12 2 views
6

Я пытаюсь изучить основы параллельных вычислений, но я столкнулся с проблемой на своем компьютере. Взгляните на мой код ниже. В принципе, я хочу распечатать строку «Hello World!». для каждого ядра моего компьютера. Мой компьютер имеет четыре ядра, поэтому он должен распечатать эту строку четыре раза. Если бы я использовал используемую прокомментированную строку 'cout' вместо строки 'printf', выход был бы все перепутан. Это происходит потому, что команда «\ n» escape выполняется отдельно от «Hello World!», Поэтому новый вывод строки будет происходить случайным образом. Линия «printf» является решением этой проблемы, потому что строка выполняется сразу (не разбивается на части, такие как строка «cout»). Однако, когда я использую 'printf', мой вывод все еще смешался, как будто я использовал 'cout'. Я понятия не имею, почему он это делает. Я пробовал точно такой же код на другом компьютере, и он отлично работает. Только мой компьютер продолжает разворачивать вывод с помощью «printf». Я по электронной почте моего профессора CS об этом, и он понятия не имеет, почему это делается на моем компьютере. Я знаю, что правильно настроил OpenMP на своем компьютере. Кто-нибудь с опытом параллельных вычислений знает, почему это испортится на моем компьютере?Параллельные вычисления - перепутал выход?

#include <omp.h> 
#include <stdio.h> 
#include <iostream> 
#include <stdlib.h> 
using namespace std; 

int main() 
{ 
    #pragma omp parallel 
    { 
     printf("Hello World!\n"); 
     //cout << "Hello World!\n" << endl; 
    } 
    return 0; 
} 

Чтобы показать, что я говорю, вот выход из когда я побежал выше код на моем компьютере:

Здравствуйте Wo

Hello World!

rld!

Hello World!

+0

Я только что пробовал с 'cout', и он работал безупречно: http://ideone.com/dPPQeO –

+0

Возможно, часть' endl' может быть источником ваших проблем, поскольку она очищает выходной буфер. –

+4

Это в значительной степени то, что вы должны ожидать, когда вы запускаете вещи параллельно. Ничего не мешает работе printf от Core 1 в середине Core 2. Это связано с тем, что параллельное программирование сложно. – immibis

ответ

6

Извините, ваш профессор ошибается. Вам необходимо использовать взаимное исключение или некоторые другие барьеры, чтобы гарантировать непрерывное использование общего ресурса (который в этом случае является выходным файлом STDOUT).

Смешанный выход - потенциально ожидаемое поведение независимо от printf или std::cout::operator<<(). Различия в поведении, которые вы видите, - это тонкие различия в продолжительности исполнения каждого из-за их различного дизайна. Вы должны ожидать такого поведения в любом случае.

Я просто не понимаю, почему он будет работать для всех остальных.

Это не так. Будьте героем своего класса и объясните, как он работает и как его исправить. Скажите им, что они посылают свою любовь. :)

4

Как уже объяснялось, предположение, что printf() является атомарным и не будет калечить ваш выход, тогда как std::cout::operator<<() не является и будет испорчено, если в корне неверно.

Однако в этом есть (крошечная) часть «истины», но на другом уровне.Позвольте мне дать вам пример:

Если я попробовать OpenMP «Привет мир» C-стиль, который может дать это:

printf("Hello from thread %d of %d\n", 
     omp_get_thread_num(), 
     omp_get_num_threads()); 

Тот же один C++ - стиль может выглядеть следующим образом:

std::cout << "Hello from thread " << omp_get_thread_num() 
      << " of " << omp_get_num_threads() 
      << std::endl; 

и существенная разница между ними состоит в том, что для printf(), я только вызов метода печати один раз, с полностью подготовленной выходной строкой, в то время как C++ - стиль один будет вызывать std::cout::operator<<() 5 раз, только с битами и кусками линий которые могут быть отправлены или не отправлены стандартный выход. Внутренне все может случиться, и я не буду пытаться совершать какие-либо действия. Но, по крайней мере, используя здесь printf(), я увеличиваю свои шансы на чистую производительность, даже если я не могу это гарантировать.

Вот полный пример:

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

int main() { 
    #pragma omp parallel 
    printf("Hello from thread %d of %d with printf()\n", 
      omp_get_thread_num(), 
      omp_get_num_threads()); 

    printf("*** outside of parallel region ***\n"); 

    #pragma omp parallel 
    std::cout << "Hello from thread " << omp_get_thread_num() 
       << " of " << omp_get_num_threads() 
       << " with std::cout" 
       << std::endl; 
    return 0; 
} 

Что на моем Linux ноутбук дает мне (GCC 5.2):

~/tmp$ g++ -fopenmp stdout.cc 
~/tmp$ ./a.out 
Hello from thread 3 of 4 with printf() 
Hello from thread 0 of 4 with printf() 
Hello from thread 2 of 4 with printf() 
Hello from thread 1 of 4 with printf() 
*** outside of parallel region *** 
Hello from thread Hello from thread Hello from thread Hello from thread 1 of 4 with std::cout23 of 4 with std::cout 
of 4 with std::cout 
0 of 4 with std::cout 

~/tmp$ 

Если вы посмотрите внимательно, вы можете увидеть, что ни один из индивидуальных вызовов до std::cout::operator<<() разделяется, но каждый новый вызов - это возможность для разных потоков участвовать в гонках друг с другом и получать результат.

Так что, опять же, заявляя, что printf() является атомарным и не испортит вещи, неправильно, но просто для сложной выходной строки он менее вероятен, чем с std::cout.

Смежные вопросы