Question

Y at-il un moyen de faire une fonction atomique dans C

Je ne suis pas à la recherche d'une solution portable (plates-formes pour la recherche - Win, Linux).

Était-ce utile?

La solution

Peut-être.

Cela dépend entièrement de votre définition de « atomique ».

  • Dans un seul noyau, environnement profondément ancré sans système d'exploitation impliqué, vous pouvez généralement désactiver et activer les interruptions. Ceci peut être utilisé pour permettre une fonction d'être atomique contre code de gestionnaire d'interruption. Mais si vous avez un bus multi-maître, un moteur DMA, ou d'un autre dispositif matériel qui peut écrire la mémoire indépendamment, alors même les interruptions de masquage peuvent ne pas fournir une assez forte garantie dans certaines circonstances.

  • Dans un environnement RTOS (temps réel du système d'exploitation), le noyau du système d'exploitation fournit généralement des primitives de synchronisation bas niveau tels que les sections critiques. Une section critique est un bloc de code qui se comporte « essentiellement » atomiquement, au moins par rapport à toutes les autres sections critiques. Il est généralement fondamental pour la mise en œuvre du système d'exploitation d'autres primitives de synchronisation.

  • Dans un environnement multi-core, un faible niveau appelé primitif spinlock est souvent disponible. Il est utilisé pour protéger contre l'entrée d'un bloc de code qui doit être atomique par rapport aux autres utilisateurs du même objet spinlock, et fonctionne en bloquant le noyau du CPU en attente dans une boucle serrée jusqu'à ce que le verrou est libéré (d'où le nom).

  • Dans de nombreux environnements de filetage, primitives plus complexes tels que les événements, les sémaphores, les mutex et les files d'attente sont fournies par le cadre de filetage. Ceux-ci coopèrent avec l'ordonnanceur de threads tels que les threads en attente de quelque chose se produise ne fonctionnent pas du tout jusqu'à ce que la condition est remplie. Ceux-ci peuvent être utilisés pour faire des actions atomiques d'une fonction par rapport à d'autres threads partageant le même objet de synchronisation.

Une règle générale serait d'utiliser les plus haut niveau des capacités disponibles dans votre environnement qui sont adaptés à la tâche. Dans le meilleur des cas, un objet sûr de fil existant, comme une file d'attente de messages peut être utilisé pour éviter d'avoir à faire quelque chose de spécial dans votre code du tout.

Autres conseils

Si vous voulez vous assurer que votre fonction ne sera pas interrompue par le signal, utilisez sigprocmask() pour masquer et démasquer les signaux, bien que certains signaux ne peuvent pas être bloqués (comme SIGKILL) et le comportement pour bloquer certains signaux (comme SIGSEGV) est indéfini.

Voir man sigprocmask pour plus de détails.

Non portably, au moins. Pour certains systèmes, vous pouvez approcher probablement, en faisant tourner des choses comme des interruptions de la machine, pour empêcher le noyau de préempter votre fonction. Mais il sera très difficile, en particulier pour les systèmes non embarqués.

Vous aurez besoin d'un soutien spécifique à la plateforme pour le faire - soit par l'utilisation de intrinsics spéciales du compilateur pour obtenir des instructions matérielles, ou en utilisant le support du système d'exploitation. Ni C ni C ++ a normalisé des choses de synchronisation.

Définir ce que vous entendez par « atomique ». Voulez-vous dire dans le sens « atomique » qu'aucun autre processus ou thread seront sélectionnés pour la planification lorsque vous exécutez votre fonction? Ou voulez-vous dire que tous les objets partagés référencés dans votre fonction ne seront pas modifiés par les autres threads pendant que votre fonction fonctionne?

Pour la première, vous ne pouvez pas vraiment contrôler que depuis l'espace utilisateur. Si vous êtes sur une machine mono-processeur, vous pouvez peut garantie atomicité en augmentant votre priorité du processus de la plus haute priorité possible (à partir du userspace). Mais même alors, il est pas garanti parce que votre algorithme de programmation peut encore permettre à un autre processus de fonctionner. Le seul moyen fiable de le faire est du système d'exploitation. Pour une machine mono-processeur vous souhaitez désactiver les interruptions. Pour une machine multi-core, vous aurez besoin de verrouiller le bus et attendre que tous les processus en cours d'exécution sur d'autres unités centrales à prendre au large.

La question est ici: Pourquoi voulez-vous garantir atomicité En général, l'exigence que seul votre processus peut être en cours d'exécution et pas d'autres, ne devrait pas exister dans l'espace utilisateur. Si vous voulez vous assurer que certaines structures de données ne sont accessibles par un fil à la fois, alors vous devriez utiliser une bibliothèque de fil portable (comme pthread par exemple), et la clôture de votre fonction en tant que section critique.

Si par atomique vous dire « un seul thread à la fois », alors vous pouvez simplement protéger la fonction avec un bloc de section critique (sous Windows). Sous Linux, j'utilise un mutex / déverrouiller à plus ou moins émuler une section critique.

Vous pouvez regarder dans sémaphores, mutex ou POSIX, etc., ce qui pourrait fonctionner sur Windows et Linux.

En utilisant par exemple Cygwin ou MinGW il est même possible d'écrire du code portable entre Linux et Windows.

Mieux encore, vous pouvez créer des fenêtres libs sur Linux: http : //cdtdoug.blogspot.com/2009/05/mingw-cross-for-linux.html

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top