Question

J'ai créé une classe de gestionnaire de mémoire tampon simple à utiliser avec des sockets asynchrones. Cela protégera contre la fragmentation de la mémoire et améliorera les performances. Avez-vous des suggestions d’améliorations ou d’autres approches?

public class BufferManager
{
    private int[] free;
    private byte[] buffer;
    private readonly int blocksize;

    public BufferManager(int count, int blocksize)
    {
        buffer = new byte[count * blocksize];
        free = new int[count];
        this.blocksize = blocksize;

        for (int i = 0; i < count; i++)
            free[i] = 1;
    }

    public void SetBuffer(SocketAsyncEventArgs args)
    {
        for (int i = 0; i < free.Length; i++)
        {
            if (1 == Interlocked.CompareExchange(ref free[i], 0, 1))
            {
                args.SetBuffer(buffer, i * blocksize, blocksize);
                return;
            }
        }
        args.SetBuffer(new byte[blocksize], 0, blocksize);
    }

    public void FreeBuffer(SocketAsyncEventArgs args)
    {
        int offset = args.Offset;
        byte[] buff = args.Buffer;

        args.SetBuffer(null, 0, 0);

        if (buffer == buff)
            free[offset / blocksize] = 1;
    }
}
Était-ce utile?

La solution

Modifier :

La réponse originale ci-dessous aborde un problème de construction de code de couplage trop étroit. Cependant, considérant la solution dans son ensemble, j’éviterais d’utiliser un seul grand tampon et de lui donner des tranches de cette façon. Vous exposez votre code à un dépassement de mémoire tampon (et nous l'appellerons des problèmes de mémoire tampon "insuffisante"). Au lieu de cela, je gérerais un tableau de tableaux d'octets, chacun étant un tampon discret. Le décalage remis est toujours égal à 0 et la taille correspond toujours à la longueur du tampon. Tout code défectueux qui tente de lire / écrire des parties au-delà des limites sera attrapé.

Réponse originale

Vous avez couplé la classe à SocketAsyncEventArgs où, en fait, tout ce dont elle a besoin est une fonction pour affecter le tampon. Modifiez SetBuffer en: -

public void SetBuffer(Action<byte[], int, int> fnSet)
{
    for (int i = 0; i < free.Length; i++)
    {
        if (1 == Interlocked.CompareExchange(ref free[i], 0, 1))
        {
            fnSet(buffer, i * blocksize, blocksize);
            return;
        }
    }
    fnSet(new byte[blocksize], 0, blocksize);
}

Vous pouvez maintenant appeler depuis un code consommateur quelque chose comme ceci: -

myMgr.SetBuffer((buf, offset, size) => myArgs.SetBuffer(buf, offset, size));

Je ne suis pas sûr que l'inférence de type soit suffisamment intelligente pour résoudre les types de buf, offset, size dans ce cas. Sinon, vous devrez placer les types dans la liste des arguments: -

myMgr.SetBuffer((byte[] buf, int offset, int size) => myArgs.SetBuffer(buf, offset, size));

Cependant, votre classe peut maintenant être utilisée pour allouer un tampon pour toutes sortes d'exigences qui utilisent également le modèle byte [], int, int qui est très courant.

Bien sûr, vous devez découpler le fonctionnement libre mais c'est: -

public void FreeBuffer(byte[] buff, int offset)
{
    if (buffer == buff)
        free[offset / blocksize] = 1;
}

Cela nécessite que vous appeliez SetBuffer sur EventArgs en utilisant du code dans le cas de SocketAsyncEventArgs . Si vous craignez que cette approche ne réduise le caractère libre de la libération du tampon et de son retrait des utilisations de sockets, sous-classe ce gestionnaire de tampon ajusté et inclut le code spécifique à SocketAsyncEventArgs dans la sous-classe.

Autres conseils

J'ai créé une nouvelle classe avec une approche complètement différente.

J'ai une classe de serveur qui reçoit des tableaux d'octets. Il invoquera ensuite différents délégués en leur remettant les objets de tampon afin que d'autres classes puissent les traiter. Lorsque ces classes sont terminées, elles ont besoin d’un moyen de remettre les tampons dans la pile.

public class SafeBuffer
{
    private static Stack bufferStack;
    private static byte[][] buffers;

    private byte[] buffer;
    private int offset, lenght;

    private SafeBuffer(byte[] buffer)
    {
        this.buffer = buffer;
        offset = 0;
        lenght = buffer.Length;
    }

    public static void Init(int count, int blocksize)
    {
        bufferStack = Stack.Synchronized(new Stack());
        buffers = new byte[count][];

        for (int i = 0; i < buffers.Length; i++)
            buffers[i] = new byte[blocksize];

        for (int i = 0; i < buffers.Length; i++)
            bufferStack.Push(new SafeBuffer(buffers[i]));
    }

    public static SafeBuffer Get()
    {
        return (SafeBuffer)bufferStack.Pop();
    }

    public void Close()
    {
        bufferStack.Push(this);
    }

    public byte[] Buffer
    {
        get
        {
            return buffer;
        }
    }

    public int Offset
    {
        get
        {
            return offset;
        }
        set
        {
            offset = value;
        }
    }

    public int Lenght
    {
        get
        {
            return buffer.Length;
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top