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 :

[.NET 2.0] Tentative pour créer un buffer circulaire lock-free


Sujet :

C#

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2011
    Messages : 14
    Points : 17
    Points
    17
    Par défaut [.NET 2.0] Tentative pour créer un buffer circulaire lock-free
    Bonjour,

    J'essaie de faire un plugin de son en C# qui utilise du réseau.
    J'ai donc besoin de faire un buffer circulaire de floats lock-free (et si possible wait-free)
    (Pour le moment, je me fiche de la généricité)

    Voici le code que j'ai actuellement :

    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    public class BufferFloatCircularLockFree
    {
        // s_ : shared
        // r_ : local read method variables (to avoid allocatation)
     
        private int             s_size;
        private float []        s_buffer;
     
        private int             s_headRead;
        private int             s_headWrite;
     
        private volatile int    r_headRead;
        private volatile int    r_headWrite;
        private volatile int    r_headCopy;
     
        public BufferFloatCircularLockFree(int size)
        {
            s_size              = size;
            s_buffer            = new float[size];
            s_headRead          = 0;
            s_headWrite         = 0;
        }
     
        public void Write(ref float f)
        {
            int headRead       = s_headRead;
            int headWrite      = s_headWrite;
     
            // queue full
            if ((headWrite + 1) % s_size == headRead % s_size)
                return;
     
            s_buffer[headWrite % s_size] = f;
     
            // no need for atomically increment here.
            s_headWrite ++;
        }
     
        public bool Read(ref float f)
        {
            do
            {
                // ensure thread safety.
                r_headRead     = s_headRead;
                r_headWrite    = s_headWrite;
     
                // queue empty or waiting
                if (r_headRead % s_size == r_headWrite % s_size)
                    return false;
     
                f = s_buffer[r_headRead % s_size];
     
                // try to perform CAS operation on the read index.
     
                // if(CAS(ref s_headRead, r_headRead, r_headRead + 1))
                if (Interlocked.CompareExchange(ref s_headRead, r_headRead, r_headRead + 1) != r_headRead)
                    return true;
     
    #error As it is now : infinite loop occurs.
     
                // didn't work. try again.
            } while (true) ;
     
            // impossible.
            //return false;
        }
     
        // CAS (Compare and swap)
        // ---------------------
        // 
        // Does atomatically :
        // 
        // public static bool CAS(ref int p, int old, int new) {
        //     if(p != old)
        //         return false;
        //     p = new;
        //     return true;
        //     // return CompareExchange (ref p, old, new) != old;
        // }
        //
        // public static bool CompareExchange(ref int location1, int value, int comparand) 
        // {
        //     if(location1 == comparand)
        //         location1 = value;
        //
        //     return location1;
        // }
     
        public bool Read(float[] data)
        {
            for (r_headCopy = 0; r_headCopy < data.Length; r_headCopy++)
                if (!Read(ref data[r_headCopy]))
                    return false;
            return true;
        }
    }
    J'ai encore du mal à voir ce qui est atomique ou non lorsque je fais mes opérations, et je me suis inspiré d'un code C++ pour faire ça.
    Le problème, comme le suggère mon #error, c'est que je me retrouve avec une boucle infinie assez rapidement.

    (on arrête pas de lire et écrire dans le buffer).

    Parmi ce que j'ai vu sur le web, il semblerait qu'il faille stocker des buffers dans une liste chaînée (et non pas les données dans un buffer).
    Or, le nombre de samples (flottants) que j'écris est différent du nombre de samples que je dois lire (ces deux comptes sont variables).
    Le problème c'est que mon thread audio doit faire le moins de calculs (pas beaucoup de temps), aucune allocation non plus et
    que mon autre thread (qui gère le réseau notamment) doit fournir les données au plus vite.

    Aucune idée de ce qui ne va pas dans le code ou dans le principe ?

    Je vous remercie d'avance,
    Sylafrs.

    NB: .NET 2.0 car oui, c'est avec Unity3D/Android :p
    Je ne peux donc pas utiliser SharedLibrary (qui utilise kernel32.dll, notemment et qui est .NET 3.5 min)
    Je vais tenter l'approche C++ si je n'y arrive pas.

  2. #2
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2011
    Messages : 14
    Points : 17
    Points
    17
    Par défaut Mauvaise interprétation de la doc
    Rebonjour,

    Il semblerait que je me sois trompé sur le fonctionnement d'Interlocked.CompareExchange :

    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    public class BufferFloatCircularLockFree
    {
        // s_ : shared
        // r_ : local read method variables (to avoid allocatation)
     
        private int             s_size;
        private float []        s_buffer;
     
        private int             s_headRead;
        private int             s_headWrite;
     
        private volatile int    r_headRead;
        private volatile int    r_headWrite;
        private volatile int    r_headCopy;
     
        public BufferFloatCircularLockFree(int size)
        {
            s_size              = size;
            s_buffer            = new float[size];
            s_headRead          = 0;
            s_headWrite         = 0;
        }
     
        public void Write(ref float f)
        {
            int headRead        = s_headRead;
            int headWrite       = s_headWrite;
     
            // queue full
            if ((headWrite + 1) % s_size == headRead % s_size)
                return;
     
            s_buffer[headWrite % s_size] = f;
     
            // no need for atomically increment here.
            s_headWrite ++;
        }
     
        public bool Read(ref float f)
        {
            do
            {
                // ensure thread safety.
                r_headRead      = s_headRead;
                r_headWrite     = s_headWrite;
     
                // queue empty or waiting
                if (r_headRead % s_size == r_headWrite % s_size)
                    return false;
     
                f = s_buffer[r_headRead % s_size];
     
                // try to perform CAS operation on the read index.
     
                // if(CAS(ref s_headRead, r_headRead, r_headRead + 1))
                if (Interlocked.CompareExchange(ref s_headRead, r_headRead + 1, r_headRead) != (r_headRead + 1))
                    return true;
     
                // didn't work. try again.
            } while (true) ;
     
            // impossible.
            //return false;
        }
     
        // CAS (Compare and swap)
        // ---------------------
        // 
        // Does atomatically :
        // 
        // public static bool CAS(ref int p, int old, int new) {
        //     if(p != old)
        //         return false;
        //     p = new;
        //     return true;
        //     // return CompareExchange (ref p, new, old) != new;
        // }
        //
        // public static bool CompareExchange(ref int location1, int value, int comparand) 
        // {
        //     int original = location1;
        //     if(location1 == comparand)
        //         location1 = value;
        //
        //     return original;
        // }
     
        public bool Read(float[] data)
        {
            for (r_headCopy = 0; r_headCopy < data.Length; r_headCopy++)
                if (!Read(ref data[r_headCopy])) // false if queue full.
                    return false; // stop the copy (we could wait ?)
            return true;
        }
    }
    Je n'ai plus de boucle infinie mais le son est mauvais.
    Ca peut venir d'autre part.

    Désolé pour ce topic :/
    Je met en résolu.

    Merci

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2011
    Messages : 14
    Points : 17
    Points
    17
    Par défaut
    Au final je me suis fait un buffer de buffer, en même temps, j'ai trouvé le moyen de fixer le nombre d'octets lus/écrits.
    Du coup, tout fonctionne au poil

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

Discussions similaires

  1. Réponses: 11
    Dernier message: 02/10/2009, 10h28
  2. Réponses: 4
    Dernier message: 23/03/2009, 11h51
  3. Réponses: 1
    Dernier message: 08/01/2009, 18h34
  4. Réponses: 6
    Dernier message: 07/12/2007, 11h29
  5. Réponses: 3
    Dernier message: 11/04/2006, 09h37

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