OpenMP 规范列出了 OpenMP 任务调度程序必须遵守的几项任务调试约束。
包括 (included) 任务生成后立即执行。
新绑定 (tied) 任务的调度受当前绑定到线程且未在屏障区域中暂停的任务区域集约束。如果此集为空,则可以调度任何新的绑定 (tied) 任务。否则,新绑定 (tied) 任务只有在它为集中各个任务的子孙任务时才会进行调度。
从属任务在其任务依赖项得到满足前不会进行调度。
当显式任务由包含 if 子句且该子句表达式求值结果为 false 的构造生成且已满足之前的约束,任务将在生成后立即执行。
如果程序还依赖任何与任务调度有关的其他假设,则程序不符合规范。
约束 1 和 4 是 OpenMP 任务应立即执行的两种情况。
约束 2 是为了防止出现死锁。在示例 4中,任务 A、B 和 C 是绑定 (tied) 任务。执行任务 A 的线程将进入临界 taskyield 区域且该线程拥有与该临界区域关联的锁。由于 taskyield 是任务调度点,因此执行任务 A 的线程可以选择暂停任务 A,改为执行其他任务。假设任务 B 和 C 在任务池中。根据约束 2,执行任务 A 的线程不能执行任务 B,因为任务 B 不是任务 A 的子孙。此时只能调度任务 C,因为任务 C 是任务 A 的子孙。
如果在暂停任务 A 的同时调度任务 B,则任务 A 所绑定到的线程无法进入任务 B 的临界区域,因为该线程已拥有与该临界区域关联的锁。因此,此时将出现死锁现象。约束 2 的目的是避免在代码符合规范时出现此类死锁现象。
请注意,如果编程人员在任务 C 中嵌套了临界段,也会发生死锁现象,但这属于编程错误。
示例 4 说明任务调度约束 2#pragma omp task // Task A { #pragma omp critical { #pragma omp task // Task C { } #pragma omp taskyield } } #pragma omp task // Task B { #pragma omp critical { } }