当多个线程读和写共享数据时,程序员必须确保这些线程不互相干涉,使得无论线程怎样被调度,程序都返回相同的结果。
因此,程序员必须管理对共享变量的读和写,以确保线程读取了正确的值,并且多个线程不在同一时间写同一个变量。
同步是管理共享资源的方法,使得无论线程怎样被调度,读和写都以正确地顺序发生。
OpenMP中主要的同步构造:
flush 它定义了一个同步点,在该点处强制了存储器的一致性。
flush语法: #pragma omp flush[ (list )]
其中list是一个由分号隔离的变量列表,这些变量需要被flush。如果该列表被省略,则对调用线程可见的所有变量将被flush。程序员很少需要调用flush,因为它被自动地插入在大多数需要它的地方。通常,程序员仅需要构造它们自己的低级同步原语。
critical 为互斥实现了一个临界区。即,在某一时刻仅有一个线程将执行临界区中的结构块。其他的线程将在该构造的顶部等待。临界区的语法如下所示:
#pragma omp critical [ ( name ) ]
{ a strucured block }
其中 name 是一个标识符,可以用于支持临界区的不相交集合。临界区暗含了在临界区的入口和出口处对flush的调用。
barrier 它提供了一个同步点,在该点处,线程将等待,直到线程组中的每一个成员到达该点之后,任意线程才能够继续执行。栅栏的语法如下所示:
#pragma omp barrier
可以显式地添加一个栅栏。但是它也经常在需要它的地方被隐式地调用(例如在并行构造或者工作分摊构造后面)。栅栏暗含了一个flush。
void omp_init_lock(omp_lock_t*lock) 它用于初始化锁。
void omp_destroy_lock(omp_lock_t*lcok) 它用于销毁锁,并且释放与锁相关的任意内存。
void omp_set_lock(omp_lock_t*lock) 它用于设置或获取锁。如果锁是空闲的,则调用omp_set_lock() 的线程将获取锁,并继续执行。如果锁被另一个线程所拥有,则调用omp_set_lock()的线程将等待,直到获得锁。
void omp_unset_lock(omp_lock_t*lock) 它用于释放锁,使得其他线程能够获取它。
void omp_test_lock(omp_lock_t*lock) 它用于测试或者查询锁是否可用。如果锁可用,则调用这个函数的线程将获取锁并继续。锁的测试和获取是自动完成的。如果锁不可用,该函数将返回false(非0),并且调用线程将继续执行。这个函数使得线程在等待锁的同时能够做一些有意义的工作。
锁函数保证了锁变量本身在线程间被一致地更新,但并不隐含对其他变量的一个flush操作。因此当需要时,使用锁的程序员必须显式地调用flush。