Переменная область в многопотативной области, почему мое ссылка на объект теряется?

StackOverflow https://stackoverflow.com/questions/4017934

Вопрос

Кратко под одним производителем - один потребительский сценарий я использовал сметный объект для синхронизации и передачи данных и сообщений между производителем и потребителем. Общий буфер - это ConcurrentQueue байтовых массивов. Для реализации циркулярного буфера и предотвратить фрагментацию кучи и частые замены объекта GC Я использовал А. ConcurrentBag байтовых массивов в качестве корзины для используемых байтовых массивов. ManualResetEventSlim используется для синхронизации потоков. Иногда я теряю ссылку на байтовые массивы в моем коде. Ниже приведена упрощенная версия моего кода, если вам нужно больше деталей, но я думаю, что это обычная ошибка при работе с потоками.

MutableObject mutableObject = new MutableObject();

Producer producer = MutableObject.GetProducer();
Consumer consumer = MutableObject.GetConsumer();

Thread fork = new Thread(new ThreadStart(producer.Start));

// Forking execution path
fork.Start();
// Main thread goes here
consumer.Start();


class MutableObject()
{
    private Producer m_producer;
    private Consumer m_consumer;
    private ConcurrentBag<byte[]> m_recycleBin = new ConcurrentBag<byte[]>();
    private ConcurrentQueue<byte[]> m_sharedBuffer = new ConcurrentQueue<byte[]>();

    public Producer GetProducer()
    {
        // Keep a reference to the mutable object
        return new Producer(this);
    }

    // GetConsumer() method is just like GetProducer() method

    public void GetEmptyBuffer(out byte[] buffer)
    {
        if (!m_recycleBin.TryTake(out buffer))
            buffer = new byte[1024];
    }

    public bool Put(byte[] buffer)
    {
        m_sharedBuffer.Enqueue(buffer);
        // Set ManualResetEventSlim for consumer
    }

    public bool Get(byte[] buffer) // Consumer calls this method in a loop
    {
        m_sharedBuffer.TryDequeue(out buffer);
        // I save a reference to buffer here and pass it to recyclebin at next call like this: lastBuffer = buffer;
        // This is because buffers are passing by refrence for I should wait until it would be used by consumer.
        m_recycleBin.Add(lastBuffer);
        // Set ManualResetEventSlim for producer
    }
}

class Producer
{
    private MutableObject m_mutableObject;

    public Producer(MutableObject mutableObject)
    {
        m_mutableObject = mutableObject;
    }

    public void Start()
    {
        byte[] buffer;

        while (true)
        {
            m_mutableObject.GetEmptyBuffer(out buffer);
            m_mutableObject.Put(buffer);
        }
    }
}

Фактически GetEmptyBuffer() Метод часто создает новые буферы, и хотя использованные буферы хранятся в корзине-корзине, счетчик корзины не воспитывает иногда!

Это было полезно?

Решение

public bool Get(byte[] buffer)

Это было бы одно очевидно, чтобы потерять ссылку. Этот метод не может на самом деле возвращать буфер, который был получен. Вам придется использовать реф ключевое слово, чтобы позволить ему вернуть массив. Трудно поверить, что настоящий код выглядит что-нибудь подобное, это просто не будет работать вообще. Есть много других красных флагов, ConcurrentBag имеет нить ассоциативность, материал теряется, если вы создадите потребительские потоки на лету. Вы не можете синхронизировать потребителя с производителем с помощью ManualResetEvent, он может сосчитать только 1.

В общем, эта оптимизация неуместна, если буферы не будут больше 85 КБ. Доверять сборщику мусора, это отличная работа, которая очень трудно улучшить.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top