轮流执行线程
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()
,在 t0
将 target
远离其初始值之前不会继续:1.
- 如果
t0
在 t1
到达其 wait()
之前执行其 notify_one()
,则 t1
的等待不会阻塞,因为 target
到那时已经是2了。
- 在那之后,两个线程总是
wait()
改变他们设置的值,这将导致他们交替。
显然,这只适用于 2 个线程。
我有一个函数只打印调用它的线程 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()
,在t0
将target
远离其初始值之前不会继续:1.- 如果
t0
在t1
到达其wait()
之前执行其notify_one()
,则t1
的等待不会阻塞,因为target
到那时已经是2了。 - 在那之后,两个线程总是
wait()
改变他们设置的值,这将导致他们交替。
显然,这只适用于 2 个线程。