IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Atomicité de l'incrémentation d'un entier.


Sujet :

C

  1. #1
    Membre actif
    Avatar de epeios
    Homme Profil pro
    Ingénieur logiciel
    Inscrit en
    Août 2003
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur logiciel

    Informations forums :
    Inscription : Août 2003
    Messages : 38
    Billets dans le blog
    2
    Par défaut Atomicité de l'incrémentation d'un entier.
    J'essaye de développer ma propre implémentation des mutexes qui soit portable, et donc sans recourir à l'assembleur, ni à une quelconque bibliothèque système (ni standard d'ailleurs). Cette implémentation s'appuye sur la fonction TryToLock() qui essaye de verrouiller un mutex, et retourne true en cas de succés (mutex verrouillé), ou false en cas d'échec (mutex déjà verrouillé, ou en cours de verrouillage par un autre thread). Elle n'est pas bloquante.

    Handler est un pointeur sur un octet initialement mis à 0.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    typedef unsigned char *mutex_handler__;
     
    int TryToLock( mutex_handler__ Handler )
    {
    	if ( *Handler != 0 )
    		return false;	// Le mutex est déjà verrouillé. On quitte en le signalant.
     
    	(*Handler)++;	// Pour signaler que l'on tente de verrouiller le mutex.
     
    	if ( *Handler > 1 )
    	{
    		// Un autre thread est en train d'essayer de verrouiller ce mutex.
    		(*Handler)--;	// On se retire de la course.
    		return false;	// On signale que l'on n'a pas réussi à verrouiller le mutex.
    	} else
    		return true;	// On signale que l'on a réussi a verrouiller le mutex.
     
    }
     
    void Unlock( mutex_handler__ Handler )
    {
    	(*Handler)--;	// Est remis à 0. Le mutex n'est plus verrouillé.
    }	// Cette fonction ne doit être appelée évidemment que sous certaines conditions (mutex verrouillé).
    Cette implémentation ne peut fonctionner que si (*Handler)++ (et accessoirement (*Handler)--) est atomique. J'aimerais donc savoir si tel est le cas. Je ne pense pas que quoi que ce soit dans la définition du langage C garantisse cela, mais, pour ce que je connais de l'assembleur et des compilateurs, je pense que cela doit être le cas. Néanmoins, j'espère qu'il se trouvera des personnes sur ce forum dont les connaissances permettront de confirmer ou d'infirmer ce que j'avance.

    En outre, un problème peut se poser si plus de 254 threads tentent d'allouer un même mutex. Bien que je n'ai pas jamais eu de logiciels qui lançaient autant de threads de manière concurrente, utiliser un unsigned short voire un unsigned long à la place de l'unsigned char écarterait définitivement ce problème. Mais qu'en est-il alors de l'atomicité de l'incrémentation et de la décrémentation ?

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Non, ce n'est pas garanti atomique.

    Sur des plate-formes spécifiques, on peut s'assurer d'utiliser des instructions assembleur atomiques sur un processeur CISC, mais sur un RISC, y'a peu de chances qu'on trouve cela...

    Généralement, les OS proposent des fonctions atomiques pour cela: sous Windows, il y a InterlockedIncrement() et InterlockedDecrement()...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Expert confirmé

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Par défaut
    Cette implémentation ne peut fonctionner que si (*Handler)++ (et accessoirement (*Handler)--) est atomique.
    C'est faux. Puisque (*Handler)++ est divisé en deux parties le chargement de la valeur de pointée par Handler, l'incrémentation puis le stockage de la nouvelle valeur. Il y a 2 endroits (en plus, je fais l'hypothèse que l'exécution d'une instruction assembleur est atomique ce qui n'est pas forcément le cas) où un thread peut s'arrêter en cours de route.

    Prenons l'exemple où un thread s'arrête juste avant le stockage.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    (*Handler) initialisé à 1
    Thread1 et Thread2 vont rentrer dans TryToLock
     
    Thread1 est en cours d'exécution, passe le premier test, commence l'incrémentation mais s'arrête avant de stocker la nouvelle valeur.
     
    Thread2 prend la main, récupère la valeur pointée par Handler: c'est toujours 0!!!
     
    Les deux vont donc passer...

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Généralement, on ne peut pas verrouiller sans une instruction assembleur de type Test-And-Set (les instructions d'incrémentation atomiques, quand il y en a, peuvent parfois être considérées comme en faisant partie).

    Ou bien, en désactivant les interruptions.

    La plupart des processeurs modernes n'ayant pas d'instruction de manipulation atomique de la mémoire, c'est généralement la seconde méthode qui est utilisée...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut Re: Atomicité de l'incrémentation d'un entier.
    Citation Envoyé par epeios
    Mais qu'en est-il alors de l'atomicité de l'incrémentation et de la décrémentation ?
    Il faut vérifier dans la norme,

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

    mais je pense qu'un opération unaire sur un type sig_atomic_t (signal.h) est insécable.

  6. #6
    Membre actif
    Avatar de epeios
    Homme Profil pro
    Ingénieur logiciel
    Inscrit en
    Août 2003
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur logiciel

    Informations forums :
    Inscription : Août 2003
    Messages : 38
    Billets dans le blog
    2
    Par défaut
    Merci à tous pour vos indications.

    Je n'ai malheureusement rien trouvé de concluant concernant l'atomicité des opérations sur un 'sig_atomic_t' ; dommage, c'eût été portable ...

    Je vais m'orienter vers 'Interlocked(In|De)crement' sous Windows (et Cygwin). Sous Linux, l'équivalent semble être 'atomic_(inc|dec)' (disponibles, semble-t'il, dans tous les noyaux de version >= 2.0), ainsi que sous BSD (à première vue).
    Il ne me reste plus qu'à trouver l'équivalent pour Mac ...

  7. #7
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Par défaut
    Bonjour,

    la glib propose un mécanisme de mutex : g_mutex_trylock / g_mutex_unlock. Cette bibliothèque étant relativement portable, le code source pourra peut être d'aider

  8. #8
    Membre actif
    Avatar de epeios
    Homme Profil pro
    Ingénieur logiciel
    Inscrit en
    Août 2003
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur logiciel

    Informations forums :
    Inscription : Août 2003
    Messages : 38
    Billets dans le blog
    2
    Par défaut
    Un examen sommaire de ces sources révèle qu'ils s'appuyent, me semble-t'il, sur une implémentation des mutexes proposée par d'autres bibliothèques ('pthread' pour Linux, 'Critical Section Objects' pour Windows). Ce que moi je ne veux pas faire, ayant besoin de différents types de mutexes.
    Merci quand même ; j'ai découvert l'existence des 'Critical Section Objects' de Windows, même si je n'en n'aurais sans doute jamais l'usage :-) !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 18
    Dernier message: 06/11/2014, 09h28
  2. Entier qui s'incrément automatiquement.
    Par Abdelouahid_alaoui dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 13/05/2014, 17h00
  3. Réponses: 6
    Dernier message: 27/08/2013, 19h14
  4. Incrémenter un string qui contient un entier
    Par itokia dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 10/06/2011, 11h56
  5. Réponses: 7
    Dernier message: 28/09/2007, 10h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo