__sync_bool_compare_and_swap 在 Cython 中使用不同的参数类型

__sync_bool_compare_and_swap with different parameter types in Cython

我正在使用 Cython 快速并行处理数据,从多个线程向共享内存链表添加项目。我使用 __sync_bool_compare_and_swap,它提供原子比较和交换 (CAS) 操作来比较值是否未被修改(由另一个线程),然后再用新值替换它。

cdef extern int __sync_bool_compare_and_swap (void **ptr, void *oldval, void *newval) nogil

cdef bint firstAttempt = 1
cdef type *next = NULL
cdef type *newlink = ....

while firstAttempt or not __sync_bool_compare_and_swap( <void**> c, <void*>next, <void*>newlink):
    firstAttempt = 0
    next = c[0]
    newlink.next = next

这个效果很好。但是,现在我也想跟踪链表的大小,并想使用相同的 CAS 函数进行更新,但是,这次需要更新的不是指针,而是一个 int。如何在 Cython 中两次使用相同的外部函数,一次使用 void** 参数,一次使用 int* 参数?

编辑

我想到的是两个独立的原子操作,一个原子操作我想更新链表,另一个我想更新大小。你可以在 C 中做到这一点,但对于 Cython 这意味着你必须使用不同的参数引用同一个外部函数两次,可以做到吗?

结论

DavidW 建议的答案有效。如果有人想使用类似的结构,你应该知道,当使用两个单独的更新函数时,不能保证它们按顺序处理(即另一个线程可以在两者之间更新),但是,如果 objective是更新一个累积值,例如在多线程时监视进度,或者创建一个在所有线程完成之前不使用的聚合结果,CAS 确实保证所有更新都只完成一次。出乎意料的是,gcc 拒绝在不转换为 void* 的情况下进行编译,因此要么定义单独的硬类型版本,要么您需要进行转换。我的代码片段:

在some_header.h中:

#define sync_bool_compare_and_swap_int __sync_bool_compare_and_swap
#define sync_bool_compare_and_swap_vp __sync_bool_compare_and_swap

在some_prog.pxd中:

cdef extern from "some_header.h":
    cdef extern int sync_bool_compare_and_swap_vp (void **ptr, void *oldval, void *newval) nogil
    cdef extern int sync_bool_compare_and_swap_int (int *ptr, int oldval, int newval) nogil

在some_prog.pyx中:

cdef void updateInt(int *value, int incr) nogil:
    cdef cINT previous = value[0]
    cdef cINT updated = previous + incr

    while not sync_bool_compare_and_swap_int( c, previous, updated):
        previous = value[0]
        updated = previous + incr

所以问题(据我所知)是它 __sync_bool_compare_and_swap 是一个编译器内在函数而不是一个函数,所以实际上没有固定的签名,因为编译器只是想出来。然而,Cython 要求知道类型,并且因为你想将它用于两种不同的类型,所以你遇到了问题。

我看不出比使用(非常)少量的 C 来 "help" Cython 更简单的方法。用一堆 #defines

创建一个 header 文件
/* compare_swap.h */
#define sync_bool_compare_swap_voidp __sync_bool_compare_and_swap
#define sync_bool_compare_swap_int __sync_bool_compare_and_swap

然后你可以告诉 Cython 这些都是一个单独的函数

cdef extern from "compare_swap.h":
    int sync_bool_compare_swap_voidp(void**, void*, void*)
    int sync_bool_compare_swap_int(int*, int, int)

在这个阶段,您应该能够自然地将它们用作普通函数而无需任何类型转换(即代码中没有 <void**>,因为这往往会隐藏真正的错误)。 C 预处理器将生成您想要的代码,一切正常。


编辑:几年后看这个,我可以看到一些你可能会使用的更简单的方法(未经测试,但我不明白为什么他们不应该工作)。首先,您可以使用 Cython 将名称映射到 "cname" 的能力,以避免需要额外的 header:

cdef extern from *:
    int sync_bool_compare_swap_voidp(void**, void*, void*) "__sync_bool_compare_and_swap"
    int sync_bool_compare_swap_int(int*, int, int) "__sync_bool_compare_and_swap"

其次(可能是最好的)你可以使用一个通用定义(只是告诉 Cython 它是一个可变参数函数):

cdef extern from "compare_swap.h":
    int __sync_bool_compare_and_swap(...)

这样 Cython 就不会试图理解所使用的类型,而只会将其完全推迟到 C(这正是您想要的)。


我不想评论您使用这样的两个原子操作是否安全,或者这是否会通过具有危险的不一致数据的状态....