Разница между задачами и разделами заключается в сроках выполнения кода. Разделы заключены в конструкцию sections
, и (если не указано условие nowait
) потоки не покинут ее, пока все разделы не будут выполнены:
[ sections ]
Thread 0: -------< section 1 >---->*------
Thread 1: -------< section 2 >*------
Thread 2: ------------------------>*------
... *
Thread N-1: ---------------------->*------
Здесь N
потоки сталкиваются с sections
конструкцией с двумя разделами, причем второй занимает больше времени, чем первый. Первые два потока выполняют по одному разделу. Остальные N-2
потоки просто ждут у неявного барьера в конце конструкции секций (показывать здесь как *
).
Задачи ставятся в очередь и выполняются, когда это возможно, в так называемых точках планирования задач. При некоторых условиях среде выполнения может быть разрешено перемещать задачу между потоками даже в середине их жизненного цикла. Такие задачи называются несвязанными, и несвязанная задача может начать выполняться в одном потоке, а затем в какой-то момент планирования она может быть перенесена средой выполнения в другой поток.
Тем не менее, задачи и разделы во многом схожи. Например, следующие два фрагмента кода дают практически одинаковый результат:
// sections
...
#pragma omp sections
{
#pragma omp section
foo();
#pragma omp section
bar();
}
...
// tasks
...
#pragma omp single nowait
{
#pragma omp task
foo();
#pragma omp task
bar();
}
#pragma omp taskwait
...
taskwait
работает очень похоже на barrier
, но для задач - он гарантирует, что текущий поток выполнения будет приостановлен до тех пор, пока все задачи в очереди не будут выполнены. Это точка планирования, то есть она позволяет потокам обрабатывать задачи. Конструкция single
нужна для того, чтобы задачи создавались только одним потоком. Если бы не было single
конструкции, каждая задача создавалась бы num_threads
раз, что может быть не тем, что нужно. Предложение nowait
в конструкции single
указывает другим потокам не ждать, пока конструкция single
будет выполнена (т. Е. Удаляет неявный барьер в конце конструкции single
). Так они сразу попадают в taskwait
и приступают к обработке задач.
taskwait
- явная точка планирования, показанная здесь для ясности. Существуют также неявные точки планирования, в первую очередь внутри барьерной синхронизации, независимо от того, явные они или неявные. Следовательно, приведенный выше код можно также записать просто как:
// tasks
...
#pragma omp single
{
#pragma omp task
foo();
#pragma omp task
bar();
}
...
Вот один из возможных сценариев того, что может произойти, если есть три потока:
+--+-->[ task queue ]--+
| | |
| | +-----------+
| | |
Thread 0: --< single >-| v |-----
Thread 1: -------->|< foo() >|-----
Thread 2: -------->|< bar() >|-----
Здесь в | ... |
показано действие точки планирования (либо директива taskwait
, либо неявный барьер). Обычно поток 1
и 2
приостанавливает свои действия в этот момент и начинает обработку задач из очереди. Как только все задачи будут обработаны, потоки возобновят свой нормальный поток выполнения. Обратите внимание, что потоки 1
и 2
могут достичь точки планирования до того, как поток 0
выйдет из конструкции single
, поэтому нет необходимости выравнивать левые |
(это показано на диаграмме выше).
Также может случиться так, что поток 1
сможет завершить обработку задачи foo()
и запросить другую еще до того, как другие потоки смогут запросить задачи. Таким образом, и foo()
, и bar()
могут выполняться одним и тем же потоком:
+--+-->[ task queue ]--+
| | |
| | +------------+
| | |
Thread 0: --< single >-| v |---
Thread 1: --------->|< foo() >< bar() >|---
Thread 2: --------------------->| |---
Также возможно, что выделенный поток может выполнить вторую задачу, если поток 2 приходит слишком поздно:
+--+-->[ task queue ]--+
| | |
| | +------------+
| | |
Thread 0: --< single >-| v < bar() >|---
Thread 1: --------->|< foo() > |---
Thread 2: ----------------->| |---
В некоторых случаях компилятор или среда выполнения OpenMP могут даже полностью обойти очередь задач и выполнить задачи последовательно:
Thread 0: --< single: foo(); bar() >*---
Thread 1: ------------------------->*---
Thread 2: ------------------------->*---
Если в коде региона нет точек планирования задач, среда выполнения OpenMP может запускать задачи, когда сочтет нужным. Например, возможно, что все задачи будут отложены до тех пор, пока не будет достигнут барьер в конце области parallel
.
person
Hristo Iliev
schedule
09.12.2012
;
в конце обоих операторов, второй код правильный. - person Hristo Iliev   schedule 09.12.2012