繁体   English   中英

omp flush的使用方法(openmp api中关于flush模型的注释如何解释)

[英]How to use omp flush(how to explain the notes in openmp api about flush model)

这是来自 openmp API 的程序。如何解释注释“标志和数据的值未定义”和“值数据将为 42,标志的值仍未定义”? 在我看来,当程序运行到“第 23 行”时,值数据应该是 42,值标志应该是 1。

//Example mem_model.2c, from Chapter 2 (The OpenMP Memory Model)
int main() {
   int data, flag = 0;
   #pragma omp parallel num_threads(2)
   {
      if (omp_get_thread_num()==0) {
         /* Write to the data buffer that will be read by thread */
         data = 42;
         /* Flush data to thread 1 and strictly order the write to data
            relative to the write to the flag */
         #pragma omp flush(flag, data)
         /* Set flag to release thread 1 */
         flag = 1;
         /* Flush flag to ensure that thread 1 sees S-21 the change */
         #pragma omp flush(flag)
      }
      else if (omp_get_thread_num()==1) {
         /* Loop until we see the update to the flag */
         #pragma omp flush(flag, data)
         while (flag < 1) {
            #pragma omp flush(flag, data)
         }
         // **line 23**
         /* **Values of flag and data are undefined** */
         printf("flag=%d data=%d\n", flag, data);
         #pragma omp flush(flag, data)
         /* **Values data will be 42, value of flag still undefined** */
         printf("flag=%d data=%d\n", flag, data);
      }
   }
   return 0;
}

由于对flag的并发非原子访问冲突,此示例包含数据竞争。 根据 OpenMP 规范,如果发生数据竞争,则“程序的结果是未指定的”。

可以在https://www.openmp.org/specifications/找到示例文档的最新版本。 该示例在示例文档的 5.0.1 版本中已更正为:

#include <omp.h>
#include <stdio.h>
int main()
{
    int data;
    int flag=0;
    #pragma omp parallel num_threads(2)
    {
      if (omp_get_thread_num()==0)
      {
      /* Write to the data buffer that will be
       * read by thread */
          data = 42;
      /* Flush data to thread 1 and strictly order
       * the write to data relative to the write to the flag */
          #pragma omp flush(flag, data)
      /* Set flag to release thread 1 */
          #pragma omp atomic write
          flag = 1;
      }
      else if(omp_get_thread_num()==1)
      {
      /* Loop until we see the update to the flag */
          #pragma omp flush(flag, data)
          int flag_val = 0;
          while (flag_val < 1)
          {
             #pragma omp atomic read
             flag_val = flag;
          }
      /* Value of flag is 1; value of data is undefined */
          printf("flag=%d data=%d\n", flag, data);
          #pragma omp flush(flag, data)
      /* Value of flag is 1; value of data is 42 */
          printf("flag=%d data=%d\n", flag, data);
      }
    }
    return 0;
}

flag变量上使用atomic构造将保证flag在退出else块中的while循环时具有值 1。 这是因为该atomic构造对原子访问的变量具有隐式刷新。 随后的flush指令将确保观察到的data值是线程 0 写入的值。如果没有该指令,memory model 允许观察data的旧值(例如,由于编译器对加载指令的重新排序或硬件)。

这是我对工作流程的理解:

线程 1 将等待标志为 1。

线程 0 会将 42 写入数据并刷新,将 1 写入标志并刷新。

当 1 被线程 0 写入标志时,它可以被线程 1 读取并中断循环(或者直到刷新)。 这会导致第 23 行出现未定义的行为。之后,刷新将确保从 memory 中读取并正确写入正确的值。

然而,当我再次测试各种版本的 GCC 和 Intel 编译器时,它总是 output 1,42 对我来说。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM