J'utilise Cython pour le traitement parallèle rapide de données, en ajoutant des éléments à une liste liée à mémoire partagée à partir de plusieurs fils. J'utilise __sync_bool_compare_and_swap, qui fournit une opération atomique de comparaison et d'échange (CAS) pour comparer si la valeur n'a pas été modifiée (par un autre thread) avant de la remplacer par une nouvelle valeur.
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
Cela fonctionne très bien. Cependant, maintenant je veux aussi garder la trace de la taille de la liste liée, et je veux utiliser la même fonction CAS pour les mises à jour, cependant, cette fois ce ne sont pas des pointeurs qui doivent être mis à jour mais un int. Comment utiliser deux fois la même fonction externe en Cython, une fois avec un paramètre void** et une fois avec un paramètre int* ?
EDIT
Ce que j'ai à l'esprit est deux opérations atomiques séparées, dans une opération atomique je veux mettre à jour la liste liée, dans l'autre je veux mettre à jour la taille. Vous pouvez le faire en C, mais pour Cython cela signifie que vous devez référencer la même fonction externe deux fois avec des paramètres différents, est-ce possible ?
CONCLUSION
La réponse proposée par DavidW fonctionne. Au cas où quelqu'un envisagerait d'utiliser une construction similaire, vous devez savoir que lorsque vous utilisez deux fonctions de mise à jour séparées, il n'y a aucune garantie qu'elles soient traitées en séquence (c'est-à-dire qu'un autre thread peut effectuer une mise à jour entre les deux), cependant, si l'objectif est de mettre à jour une valeur cumulative, par exemple pour surveiller la progression en multithreading ou pour créer un résultat agrégé qui n'est pas utilisé avant que tous les threads aient terminé, CAS garantit que toutes les mises à jour sont effectuées exactement une fois. De manière inattendue, gcc refuse de compiler sans casting vers void*, donc soit vous définissez des versions séparées et typées en dur, soit vous devez faire un cast. Un extrait de mon code :
dans 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
dans 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
dans 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