В качестве отправной точки я бы предложил OpenMP. При этом вы можете очень просто выполнить три основных типа параллелизма: циклы , секции и задачи .
Параллельные петли
Они позволяют вам разделять итерации цикла на несколько потоков. Например:
#pragma omp parallel for
for (int i=0; i<N; i++) {...}
Если бы вы использовали два потока, то первый поток выполнял бы первую половину итерации. Второй поток будет выполнять вторую половину.
Разделы
Они позволяют вам статически разделить работу на несколько потоков. Это полезно, когда есть очевидная работа, которая может выполняться параллельно. Однако это не очень гибкий подход.
#pragma omp parallel sections
{
#pragma omp section
{...}
#pragma omp section
{...}
}
Задачи
Задачи являются наиболее гибким подходом. Они создаются динамически, и их выполнение выполняется асинхронно, либо потоком, который их создал, либо другим потоком.
#pragma omp task
{...}
Преимущества
OpenMP предлагает несколько вещей.
На основе директив: компилятор выполняет работу по созданию и синхронизации потоков.
Инкрементальный параллелизм: Вы можете сосредоточиться только на той области кода, которую нужно распараллелить.
Одна исходная база для последовательного и параллельного кода: Директивы OpenMP распознаются компилятором только при запуске его с флагом (-fopenmp
для gcc), Таким образом, вы можете использовать одну и ту же исходную базу для генерации как последовательного, так и параллельного кода. Это означает, что вы можете отключить флаг, чтобы увидеть, получаете ли вы тот же результат от серийной версии кода или нет. Таким образом, вы можете изолировать ошибки параллелизма от ошибок в алгоритме.
Вы можете найти всю спецификацию OpenMP по адресу http://www.openmp.org/