我试图在我的代码中实现一个简单的屏障,如下所示:
void waitOnBarrier(int* barrier, int numberOfThreads) {
atomicIncrement(barrier); // atomic increment implemented in assembly
while(*barrier < numberOfThreads);
}
然后代码中有一个屏障用法:
int g_barrier = 0; // a global variable
waitOnBarrier(&g_barrier, someKnownNumberOfThreads);
到目前为止一切顺利,但我应该在哪里将我的g_barrier变量重置为零?如果我写类似
g_barrier = 0;
在waitOnBarrier调用之后,如果其中一个线程比其他线程更快地从屏障中释放并在所有其他线程仍在执行循环指令时使g_barrier无效,那么我将遇到问题,因此最终它们将永远卡在屏障上.
解释: waitOnBarrier会编译成这样的东西(伪代码):
1: mov rax, numberOfThreads
2: mov rbx, [barrier]
3: cmp rax, rbx
4: jmp(if smaller) to 2
因此,如果我们有 2 个线程在屏障上同步,并且thread_1在指令 3 或 4 的某处变慢,而更快的thread_2到达屏障,通过它并继续到g_barrier无效流程。这意味着在thread_1到达指令 2 之后,它将在 [barrier] 处看到零值,并将永远卡在屏障上!
问题是,我应该如何取消g_barrier,它在代码中的哪个位置“足够远”,我可以确定到那时所有线程都离开了屏障?还是有更正确的方法来实施障碍?