轮流执行线程

Executing threads taking turns

我有一个函数只打印调用它的线程 ID。我想让2个线程轮流调用这个函数n次。我已经在带有条件变量的 pthreads 中实现了这个功能,但它太冗长了。我希望程序打印如下:

id: 0
id: 1
id: 0
id: 1
id: 0
id: 1
...

最后应该打印n次"id:0"和"id:1"

执行此 OpenMP 的惯用方法是什么?

您可以根据迭代计数检查线程数,并使用障碍实现切换。

#include <omp.h>

#include <cstdio>


int main()
{
  /* note that it is not pragma omp parallel for, just a parallel block */
# pragma omp parallel num_threads(2)
  for(int i = 0; i < 10; ++i) {
    if((i & 1) == (omp_get_thread_num() & 1))
      std::printf("%d: thread %d\n", i, omp_get_thread_num());
#   pragma omp barrier
  }
}

由于 OP 提到这是用于基准测试跨核延迟,因此至少应该考虑纯粹基于 std::atomic 的解决方案。

使用 C++20 的 wait(),我们可以执行以下操作:

#include <thread>
#include <atomic>
#include <iostream>

std::atomic<int> target(1);

void worker(int wid, int n) {
  int v = wid;

  for (int i = 0; i < n; ++i) {    
    target.wait(v);       // wait until target has a different value than v

    // Do stuff...    
    // std::cout << wid;

    v = target.load() + 1;
    target.store(v);      // increment target
    target.notify_one();  // Wakeup the other thread.
  }
}

int main() {
  int n = 100;

  std::jthread t0(worker, 0, n);
  std::jthread t1(worker, 1, n);
}

诚然,这在引导过程中有点靠谱。 这是发生了什么:

  • t0 的第一个 wait() 将立即通过,因为 0 != 1,没有什么可以事先改变 target
  • t1 的第一个 wait(),在 t0target 远离其初始值之前不会继续:1.
  • 如果 t0t1 到达其 wait() 之前执行其 notify_one(),则 t1 的等待不会阻塞,因为 target 到那时已经是2了。
  • 在那之后,两个线程总是wait() 改变他们设置的值,这将导致他们交替。

显然,这只适用于 2 个线程。