我正在编写一个C库,我想通过使用OpenMP来选择性地支持并发(如果编译器不支持OpenMP,可以串行编译它)。我想使用无锁堆栈实现。
我考虑过使用C的stdatomic.h
作为堆栈,但似乎是until a few weeks ago, GCC couldn't use _Atomic
with OpenMP,所以这会使可移植性变得复杂。 Clang 3.8似乎正确地使用OpenMP处理原子,但是这仍然不是最好的选择,因为在没有OpenMP(因此是连续的)编译时没有必要保持原子性。
我似乎需要在从堆栈弹出时使用比较和交换操作,而我在OpenMP上找不到任何有关比较和交换的信息。有没有办法只使用OpenMP实现无锁堆栈?
到目前为止我的代码(与clang合作):
struct lfstack_node {
void *value;
struct lfstack_node *next;
};
typedef struct lfstack {
_Atomic(size_t) size;
_Atomic(struct lfstack_node *) head;
_Atomic int aba;
} *lfstack_t;
// ...
void *lfstack_pop(lfstack_t stack) {
if(stack) {
atomic_fetch_add(&stack->aba, 1);
struct lfstack_node *node, *next;
do {
node = atomic_load(&stack->head);
if(!node) {
break;
}
// ABA problem here if not handled correctly
next = node->next;
} while(!atomic_compare_exchange_weak(&stack->head, &node, next));
atomic_fetch_sub(&stack->aba, 1);
if(node) {
int zero = 0;
while(!atomic_compare_exchange_weak(&stack->aba, &zero, zero)) {
continue;
}
void *value = node->value;
free(node);
return value;
}
}
return NULL;
}