Несколько потоков обращаются к методу возврата. Безопасен ли поток с помощью блокировки? - PullRequest
2 голосов
/ 26 июня 2019

Я пытаюсь получить доступ к методу из нескольких потоков, я не уверен, что это потокобезопасный.Если это не так, каков будет самый эффективный способ сделать его безопасным?

Я учел мнение каждого, мой конечный продукт может быть показан ниже, я также решил вызвать recycle на самом пакете.

Мой класс пула пакетов

using System.Collections.Generic;

namespace Networking
{
    public class PacketPool
    {
        private Queue<Packet> pool = new Queue<Packet>();
        private readonly object instance = new object();

        public Packet CreatePacket(string method)
        {
            lock (instance)
                return pool.Count == 0 ? new Packet() { Pool = this } : 
                       pool.Dequeue();
        }

        public void Recycle(Packet packet)
        {
            lock(instance)
               pool.Enqueue(packet);
        }
    }
}

Класс пакета

using System;
using System.Net;

namespace Networking
{
    public class Packet 
    {
        public Protocol Proto = Protocol.Sequenced;
        public PacketFlags Flag = PacketFlags.None;
        public Fragment Fragmented = Fragment.NotFragged;
        public SendType SendType = SendType.Raw;
        public EndPoint RemoteEp = new IPEndPoint(IPAddress.Any, 0);
        public byte[] Buffer = new byte[512];
        public int Count = 0;
        public int Ptr = 8;
        public int Bits { get; set; } = 0;
        public ushort Id = 0;
        public ushort Lead = 0;
        public PacketPool Pool;

        public void Recycle()
        {
            Bits = 0;

            if (Buffer.Length > 512)
                Array.Resize(ref Buffer, 512);

            Count = 0;
            Flag = PacketFlags.None;
            Fragmented = Fragment.NotFragged;
            Proto = Protocol.Sequenced;
            Ptr = 8;
            Lead = 0;
            SendType = SendType.Raw;
            Pool.Recycle(this);
        }
    }
}

Надеясь, что решение, описанное выше, облегчит жизнь.

Ответы [ 2 ]

4 голосов
/ 26 июня 2019

Код, который вы показали, выглядит потокобезопасным, если сами пакеты не модифицируются в отдельных потоках.Можно также подумать о том, чтобы сделать класс PacketPool потокобезопасным, чтобы сэкономить драгоценное время блокировки.

Вы можете упростить его, заменив Queue на ConcurrentQueue.

Обратите внимание, что вы модифицируете пакет, отправленный в метод Recycle.Я бы рекомендовал сделать объекты данных неизменяемыми, чтобы избежать непредвиденного поведения.

public class PacketPool
{
    public ConcurrentQueue<Packet> pool = new ConcurrentQueue<Packet>(2000);

    public Packet CreatePacket(string method)
    {
        if (pool.TryDequeue(out Packet packet))
        {
            return packet;
        }

        return new Packet();
    }

    public void Recycle(Packet packet)
    {
        packet.Bits = 0;

        if (packet.Buffer.Length > 512)
            Array.Resize(ref packet.Buffer, 512);

        packet.Count = 0;
        packet.Flag = PacketFlags.None;
        packet.Fragmented = Fragment.NotFragged;
        packet.Proto = Protocol.Sequenced;
        packet.Ptr = 8;
        packet.Lead = 0;
        packet.SendType = SendType.Raw;
        pool.Enqueue(packet);
    }
}
1 голос
/ 26 июня 2019

Если пакет не распределяется между потоками, это обеспечивает безопасность потоков благодаря блокировкам.

Будьте осторожны с публичным полем.Вы можете также отредактировать, что по теме небезопасно.

Обратите внимание, что рекомендуется выделенный объект блокировки, в противном случае может стать тупиком - например, другой процесс блокирует открытое свойство Pool.Рекомендуется сделать объект блокировки частным и использовать его только в этом классе (на один уровень выше)

Когда вы синхронизируете доступ потоков к общему ресурсу, блокируйте выделенный экземпляр объекта (например, частныйreadonly object balanceLock = new object ();) или другой экземпляр, который вряд ли будет использоваться в качестве объекта блокировки несвязанными частями кода.Избегайте использования одного и того же экземпляра объекта блокировки для разных общих ресурсов, так как это может привести к взаимоблокировке или конфликту блокировки.

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...