Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何确保多线程编程中的执行顺序?_C++_C_Multithreading_Openmp - Fatal编程技术网

C++ 如何确保多线程编程中的执行顺序?

C++ 如何确保多线程编程中的执行顺序?,c++,c,multithreading,openmp,C++,C,Multithreading,Openmp,以下多线程代码中是否存在任何问题?它总是给我不一致的结果。编译器优化可能会将标志设置行移到数据处理行之前,从而导致严重的数据争用情况 有没有办法在不增加障碍的情况下避免这种情况 #pragma omp parallel num_threads(16) int tid=omp_get_thread_num(); if (tid<8) { copydata(arrayofPtrs[tid]); flag[tid]=1;//flag is an array of volatil

以下多线程代码中是否存在任何问题?它总是给我不一致的结果。编译器优化可能会将标志设置行移到数据处理行之前,从而导致严重的数据争用情况

有没有办法在不增加障碍的情况下避免这种情况

#pragma omp parallel num_threads(16)

int tid=omp_get_thread_num();

if (tid<8)
{
   copydata(arrayofPtrs[tid]);

   flag[tid]=1;//flag is an array of volatile int where its initial values are all 0.

}
else
{
   for (int i=0; i<100000; ++i)
   {
     if (flag[tid-8]==1)
      {
       processingdata(arrayofPtrs[tid-8]);
       break;
       }
     else
       Sleep(200);
   };
};
#pragma omp并行num_线程(16)
int tid=omp_get_thread_num();

如果(tid您可以在处理线程的标记测试周围使用一个循环,这样它们将在标记上旋转锁,直到它被设置。但是,这部分代码看起来是连续的,那么为什么要使用多个线程进行复制/处理呢?您可以用一个线程进行复制,然后用同一个线程继续处理该块。

rstand您的代码,除非数据已被复制,否则数据处理无法继续,因此并行执行没有意义-处理线程将浪费CPU时间等待复制线程完成并设置标志。然后,为什么不将两个操作合并到一个块中:

#pragma omp parallel num_threads(8)
{
   int tid = omp_get_thread_num();

   copydata(arrayofPtrs[tid]);
   processingdata(arrayofPtrs[tid]);
}
如果您仍想保留您的原始想法,可能是复制和处理都以异步和重复的方式进行,那么您需要使用Open MP
atomic
操作同步对标志的访问:

#pragma omp parallel num_threads(16)
{
   int tid = omp_get_thread_num();

   if (tid < 8)
   {
      copydata(arrayofPtrs[tid]);

      #pragma omp atomic write
      flag[tid] = 1;//flag is an array of volatile int where its initial values are all 0.
   }
   else
   {
      for (int i = 0; i < 100000; ++i)
      {
         #pragma omp atomic read
         int ready = flag[tid-8];
         if (ready == 1)
         {
            processingdata(arrayofPtrs[tid-8]);
            break;
         }
         else
            Sleep(200);
      }
   }
}
read
write
子句仅在最新的OpenMP版本上受支持。此
Sleep()
看起来您使用的是Win32 API,因此可能使用的是MSVC,它不支持
read
write
修饰符,因为它只实现OpenMP 2.0,但代码仍应按预期编译和工作

不使用繁忙循环的另一种可能方法是使用OpenMP锁。初始化锁数组,在复制线程中获取它们,然后让每个处理线程等待获取锁:

omp_lock_t locks[8];
for (int i = 0; i < 8; i++)
   omp_init_lock(&locks[i]);

#pragma omp parallel num_threads(16)
{
    int tid = omp_get_thread_num();

    // Have the first 8 threads acquire the locks
    if (tid < 8)
       omp_set_lock(&locks[tid]);

    #pragma omp barrier

    // Now locks are set and processing can continue

    if (tid < 8)
    {
       copydata(arrayofPtrs[tid]);
       omp_unset_lock(&locks[tid]);
    }
    else
    {
       omp_set_lock(&locks[tid-8]);
       processingdata(arrayofPtrs[tid-8]);
       omp_unset_lock(&locks[tid-8]);
    }
 }

 for (int i = 0; i < 8; i++)
    omp_destroy_lock(&locks[i]);
omp__t locks[8];
对于(int i=0;i<8;i++)
omp_init_lock(&locks[i]);
#pragma omp并行num_线程(16)
{
int tid=omp_get_thread_num();
//让前8个线程获得锁
如果(tid<8)
omp_set_lock(&locks[tid]);
#布拉格奥姆普屏障
//现在已设置锁,处理可以继续
如果(tid<8)
{
copydata(arrayofPtrs[tid]);
omp_unset_lock(&locks[tid]);
}
其他的
{
omp_set_lock(&locks[tid-8]);
处理数据(arrayofPtrs[tid-8]);
omp_unset_lock(&locks[tid-8]);
}
}
对于(int i=0;i<8;i++)
omp_destroy_lock(&locks[i]);

您还可以使用POSIX信号量的Win32事件而不是OpenMP锁来实现相同的功能。这种方法的优点是,在等待设置标志时不需要显式循环。而是使用
omp\u set\u lock()
调用将被阻止,直到复制线程释放其锁。对于Win32事件,您可以使用
WaitForSingleObject(hEvent,INFINITE)
等待复制线程发出信号。

是的,编译器可以移动指令的顺序。这就是在语言中添加障碍的明显原因-允许程序员确保所需的顺序。Volatile在这种情况下没有帮助。@PeterR:我的代码中已经有太多障碍了,我真的很抱歉顺便说一句,我之所以添加volatile关键字是为了防止编译器优化代码以将标志数据加载到寄存器中。volatile不做您认为它做的事情。您需要使用c++11或c11原子或omp屏障。volatile禁用寄存器分配,但不禁止编译器移动t他复制数据设置标志后调用。volatile用于访问设备寄存器,它在并行代码中没有位置。Michael编辑了我的线程,很糟糕一些信息被编辑掉了,实际上这段代码只是显示了algorthim的概念,而不是真正的代码,这段代码很长,并且做了很多其他事情。不过,我不明白为什么你想在不同的线程中进行复制和处理。但只要你只设置了一个方向的标志形式,你就可以使用忙等待。我没有碰你的代码@user2188453;我只是复制编辑过的你的散文。你可以查看编辑历史,看看我做了什么-单击“编辑的X分钟前”链接。
omp_lock_t locks[8];
for (int i = 0; i < 8; i++)
   omp_init_lock(&locks[i]);

#pragma omp parallel num_threads(16)
{
    int tid = omp_get_thread_num();

    // Have the first 8 threads acquire the locks
    if (tid < 8)
       omp_set_lock(&locks[tid]);

    #pragma omp barrier

    // Now locks are set and processing can continue

    if (tid < 8)
    {
       copydata(arrayofPtrs[tid]);
       omp_unset_lock(&locks[tid]);
    }
    else
    {
       omp_set_lock(&locks[tid-8]);
       processingdata(arrayofPtrs[tid-8]);
       omp_unset_lock(&locks[tid-8]);
    }
 }

 for (int i = 0; i < 8; i++)
    omp_destroy_lock(&locks[i]);