在本篇文章當中主要給大家介紹在 OpenMP 當中 guided 排程方式的實現原理。這個排程方式其實和 dynamic 排程方式非常相似的,從編譯器角度來說基本上是一樣的,在本篇文章當中就不介紹一些相關的必備知識了,如果不瞭解可以先看這篇文章 OpenMP For Construct dynamic 排程方式實現原理和原始碼分析 。
我們使用下面的程式碼來分析一下 guided 排程的情況下整個程式的執行流程是怎麼樣的:
#pragma omp parallel for num_threads(t) schedule(guided, size)
for (i = lb; i <= ub; i++)
body;
編譯器會將上面的程式編譯成下面的形式:
void subfunction (void *data)
{
long _s0, _e0;
while (GOMP_loop_guided_next (&_s0, &_e0))
{
long _e1 = _e0, i;
for (i = _s0; i < _e1; i++)
body;
}
// GOMP_loop_end_nowait 這個函數的主要作用就是釋放資料的記憶體空間 在後文當中不進行分析
GOMP_loop_end_nowait ();
}
GOMP_parallel_loop_guided_start (subfunction, NULL, t, lb, ub+1, 1, size);
subfunction (NULL);
// 這個函數在前面的很多文章已經分析過 本文也不在進行分析
GOMP_parallel_end ();
根據上面的程式碼可以知道,上面的程式碼當中最主要的兩個函數就是 GOMP_parallel_loop_guided_start 和 GOMP_loop_guided_next,現在我們來分析一下他們的原始碼:
void
GOMP_parallel_loop_guided_start (void (*fn) (void *), void *data,
unsigned num_threads, long start, long end,
long incr, long chunk_size)
{
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
GFS_GUIDED, chunk_size);
}
static void
gomp_parallel_loop_start (void (*fn) (void *), void *data,
unsigned num_threads, long start, long end,
long incr, enum gomp_schedule_type sched,
long chunk_size)
{
struct gomp_team *team;
// 解析到底啟動幾個執行緒執行並行域的程式碼
num_threads = gomp_resolve_num_threads (num_threads, 0);
// 建立執行緒組
team = gomp_new_team (num_threads);
// 對共用資料進行初始化操作
gomp_loop_init (&team->work_shares[0], start, end, incr, sched, chunk_size);
// 啟動執行緒組執行函數 fn
gomp_team_start (fn, data, num_threads, team);
}
在上面的程式當中 GOMP_parallel_loop_guided_start,有 7 個引數,我們接下來仔細解釋一下這七個引數的含義: