пятница, 12 сентября 2025 г.

25.09.12, ConcurrentCircularBuffer, CS, Alice

ConcurrentCircularBuffer, CS, Alice

Вот реализация кольцевого буфера (Circular Buffer) на C#:

csharp

public class CircularBuffer<T>

{

    private T[] buffer;

    private int start = 0;    // Индекс начала буфера

    private int count = 0;    // Количество элементов в буфере

    private readonly int capacity;    // Максимальная вместимость

 

    // Конструктор

    public CircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

           

        capacity = size;

        buffer = new T[size];

    }

 

    // Добавление элемента в буфер

    public void Enqueue(T item)

    {

        if (count == capacity)

            throw new InvalidOperationException("Буфер переполнен");

 

        int end = (start + count) % capacity;

        buffer[end] = item;

        count++;

    }

 

    // Извлечение элемента из буфера

    public T Dequeue()

    {

        if (count == 0)

            throw new InvalidOperationException("Буфер пуст");

 

        T item = buffer[start];

        start = (start + 1) % capacity;

        count--;

        return item;

    }

 

    // Получение элемента по индексу

    public T Peek(int index)

    {

        if (index < 0 || index >= count)

            throw new IndexOutOfRangeException();

 

        return buffer[(start + index) % capacity];

    }

 

    // Очистка буфера

    public void Clear()

    {

        start = 0;

        count = 0;

    }

 

    // Текущая длина буфера

    public int Count => count;

 

    // Максимальная вместимость

    public int Capacity => capacity;

 

    // Проверка на пустоту

    public bool IsEmpty => count == 0;

 

    // Проверка на заполненность

    public bool IsFull => count == capacity;

}

Объяснение работы кода

Основные компоненты:

  • buffer — массив для хранения элементов
  • start — индекс начала буфера
  • count — количество элементов в буфере
  • capacity — максимальная вместимость

Методы класса

  • Конструктор инициализирует буфер заданного размера
  • Enqueue добавляет элемент в конец буфера
  • Dequeue извлекает элемент из начала буфера
  • Peek возвращает элемент по указанному индексу без удаления
  • Clear очищает буфер
  • Count возвращает текущее количество элементов
  • Capacity возвращает максимальную вместимость
  • IsEmpty проверяет, пуст ли буфер
  • IsFull проверяет, заполнен ли буфер

Пример использования

csharp

var buffer = new CircularBuffer<int>(5);

buffer.Enqueue(1);

buffer.Enqueue(2);

buffer.Enqueue(3);

 

Console.WriteLine(buffer.Dequeue()); // Выведет 1

Console.WriteLine(buffer.Peek(0));   // Выведет 2

 

buffer.Enqueue(4);

buffer.Enqueue(5);

buffer.Enqueue(6);  // Перезапишет первый элемент

Этот кольцевой буфер эффективно использует память и обеспечивает постоянную сложность операций добавления и удаления элементов O(1).

Добавь в код Кольцевого буфера меры синхронизации для конкурентного использования твоей реализации Кольцевого буфера

Вот реализация потокобезопасного кольцевого буфера на C#:

csharp

using System;

using System.Collections.Generic;

using System.Threading;

 

public class ThreadSafeCircularBuffer<T>

{

    private readonly T[] buffer;

    private int start = 0; // Индекс начала буфера

    private int count = 0; // Количество элементов в буфере

    private readonly int capacity; // Максимальная вместимость

   

    // Мьютекс для синхронизации доступа

    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

 

    // Конструктор

    public ThreadSafeCircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

       

        capacity = size;

        buffer = new T[size];

    }

 

    // Добавление элемента в буфер

    public void Enqueue(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == capacity)

                throw new InvalidOperationException("Буфер переполнен");

 

            int end = (start + count) % capacity;

            buffer[end] = item;

            count++;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Извлечение элемента из буфера

    public T Dequeue()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            T item = buffer[start];

            start = (start + 1) % capacity;

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Получение элемента по индексу

    public T Peek(int index)

    {

        _lock.EnterReadLock();

        try

        {

            if (index < 0 || index >= count)

                throw new IndexOutOfRangeException();

 

            return buffer[(start + index) % capacity];

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Очистка буфера

    public void Clear()

    {

        _lock.EnterWriteLock();

        try

        {

            start = 0;

            count = 0;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Текущая длина буфера

    public int Count

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

 

    // Максимальная вместимость

    public int Capacity => capacity;

 

    // Проверка на пустоту

    public bool IsEmpty

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count == 0;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

 

    // Проверка на заполненность

    public bool IsFull

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count == capacity;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

}

Объяснение добавленных изменений

1.  ReaderWriterLockSlim — используется для синхронизации доступа к буферу:

o    Позволяет множественный параллельный доступ для чтения

o    Обеспечивает эксклюзивный доступ для записи

2.  Блокировки:

o    EnterWriteLock()/ExitWriteLock() — для операций модификации (Enqueue, Dequeue, Clear)

o    EnterReadLock()/ExitReadLock() — для операций чтения (Peek, Count, IsEmpty, IsFull)

3.  Обработка исключений:

o    Использование блока try-finally гарантирует освобождение блокировки даже при возникновении исключений

Рекомендации по использованию

  • При работе с буфером в многопоточной среде используйте try-catch для обработки возможных исключений
  • Избегайте длительных операций внутри блокировок
  • При необходимости можно добавить методы с таймаутами для попыток получения блокировки

Пример использования в многопоточной среде

csharp

var buffer = new ThreadSafeCircular

Добавь в Код твоей реализации Кольцевого буфера Два Итератора. Чтобы можно было бы читать и писать из разных направлений (сторон) Слева и Справа - Слева IteratorReadFromLeft, IteratorWriteToLeft, - Срава IteratorReadFromRight, IteratorWriteToRight

Вот реализация кольцевого буфера с поддержкой двустороннего итеративного доступа:

csharp

using System;

using System.Collections.Generic;

using System.Threading;

 

public class ThreadSafeCircularBuffer<T>

{

    private readonly T[] buffer;

    private int start = 0; // Индекс начала буфера

    private int count = 0; // Количество элементов в буфере

    private readonly int capacity; // Максимальная вместимость

   

    // Мьютекс для синхронизации доступа

    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

   

    // Индексы для двустороннего доступа

    private int leftWriteIndex = 0;

    private int rightWriteIndex = 0;

    private int leftReadIndex = 0;

    private int rightReadIndex = 0;

 

    // Конструктор

    public ThreadSafeCircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

       

        capacity = size;

        buffer = new T[size];

    }

 

    // Добавление элемента в буфер слева

    public void EnqueueLeft(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == capacity)

                throw new InvalidOperationException("Буфер переполнен");

 

            int index = (leftWriteIndex - 1 + capacity) % capacity;

            buffer[index] = item;

            leftWriteIndex = index;

            count++;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Добавление элемента в буфер справа

    public void EnqueueRight(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == capacity)

                throw new InvalidOperationException("Буфер переполнен");

 

            int index = rightWriteIndex;

            buffer[index] = item;

            rightWriteIndex = (index + 1) % capacity;

            count++;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение элемента слева

    public T DequeueLeft()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            T item = buffer[leftWriteIndex];

            leftWriteIndex = (leftWriteIndex + 1) % capacity;

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение элемента справа

    public T DequeueRight()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            int index = (rightWriteIndex - 1 + capacity) % capacity;

            T item = buffer[index];

            rightWriteIndex = index;

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Итератор для чтения слева

    public IEnumerator<T> IteratorReadFromLeft()

    {

        _lock.EnterReadLock();

        try

        {

            int currentIndex = leftReadIndex;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[currentIndex];

                currentIndex = (currentIndex + 1) % capacity;

                elementsRead++;

            }

           

            leftReadIndex = currentIndex;

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Итератор для записи слева

    public void IteratorWriteToLeft(IEnumerable<T> items)

    {

        _lock.EnterWriteLock();

        try

        {

            foreach (var item in items)

            {

                if (count == capacity)

                    throw new InvalidOperationException("Буфер переполнен");

 

                int index = (leftWriteIndex - 1 + capacity) % capacity;

                buffer[index] = item;

                leftWriteIndex = index;

                count++;

            }

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Итератор для

Напиши теперь примеры использования твоего Применения Кольцевого Буфера. - Запись слева, Чтение слева, Запись справа, Чтение справа в разных сочетаниях

Примеры использования кольцевого буфера

Пример 1: Базовая работа с буфером

csharp

var buffer = new ThreadSafeCircularBuffer<string>(5);

 

// Запись слева и чтение слева

buffer.EnqueueLeft("Левый элемент 1");

buffer.EnqueueLeft("Левый элемент 2");

 

Console.WriteLine(buffer.DequeueLeft()); // Выведет "Левый элемент 2"

Console.WriteLine(buffer.DequeueLeft()); // Выведет "Левый элемент 1"

 

// Запись справа и чтение справа

buffer.EnqueueRight("Правый элемент 1");

buffer.EnqueueRight("Правый элемент 2");

 

Console.WriteLine(buffer.DequeueRight()); // Выведет "Правый элемент 2"

Console.WriteLine(buffer.DequeueRight()); // Выведет "Правый элемент 1"

Пример 2: Комбинированное использование

csharp

var buffer = new ThreadSafeCircularBuffer<int>(10);

 

// Заполняем буфер с разных сторон

buffer.EnqueueLeft(1);

buffer.EnqueueLeft(2);

buffer.EnqueueRight(3);

buffer.EnqueueRight(4);

 

// Читаем слева

Console.WriteLine("Чтение слева:");

foreach (var item in buffer.IteratorReadFromLeft())

{

    Console.WriteLine(item);

}

 

// Читаем справа

Console.WriteLine("\nЧтение справа:");

buffer.EnqueueRight(5);

buffer.EnqueueRight(6);

 

int rightItem = buffer.DequeueRight();

Console.WriteLine(rightItem); // Выведет 6

 

rightItem = buffer.DequeueRight();

Console.WriteLine(rightItem); // Выведет 5

Пример 3: Массовое добавление элементов

csharp

var buffer = new ThreadSafeCircularBuffer<string>(10);

 

// Массовое добавление слева

List<string> leftItems = new List<string> { "A", "B", "C" };

buffer.IteratorWriteToLeft(leftItems);

 

// Массовое добавление справа

List<string> rightItems = new List<string> { "X", "Y", "Z" };

buffer.IteratorWriteToRight(rightItems);

 

// Чтение всех элементов

Console.WriteLine("Содержимое буфера:");

foreach (var item in buffer.IteratorReadFromLeft())

{

    Console.WriteLine(item);

}

Пример 4: Работа в многопоточной среде

csharp

var buffer = new ThreadSafeCircularBuffer<int>(20);

 

// Поток для записи слева

Task.Run(() =>

{

    for (int i = 1; i <= 10; i++)

    {

        buffer.EnqueueLeft(i);

        Thread.Sleep(100);

    }

});

 

// Поток для записи справа

Task.Run(() =>

{

    for (int i = 100; i >= 91; i--)

    {

        buffer.EnqueueRight(i);

        Thread.Sleep(150);

    }

});

 

// Поток для чтения слева

Task.Run(() =>

{

    Thread.Sleep(500); // Ждем заполнения буфера

    while (!buffer.IsEmpty)

    {

        Console.WriteLine($"Чтение слева: {buffer.DequeueLeft()}");

        Thread.Sleep(200);

    }

});

 

// Поток для чтения справа

Task.Run(() =>

{

    Thread.Sleep(500); // Ждем заполнения буфера

    while (!buffer.IsEmpty)

    {

        Console.WriteLine($"Чтение справа: {buffer.DequeueRight()}");

        Thread.Sleep(200);

    }

});

 

Console.ReadLine();

Практические сценарии использования

1.  Буферизация данных в реальном времени:

  • Прием данных с датчиков с разных источников
  • Обработка потоковых данных
  • Кэширование промежуточных результатов

2.  Межпоточная коммуникация:

  • Очередь сообщений между producer и consumer
  • Буферизация событий в системе мониторинга
  • Синхронизация данных между потоками

3.  Обработка данных:

  • Буферизация при преобразовании данных
  • Временное хранение результатов вычислений
  • Кэширование часто используемых значений

Важные моменты при использовании

  • Всегда проверяйте заполненность буфера перед записью
  • Обрабатывайте исключения при переполнении
  • Используйте итераторы для массовой обработки данных
  •  

В данной реализации Переполнения быть не должно. МЫ должны всегда иметь возможность записать новый элемент Слева или Справа с удалением противоположного элемента. Пример применения Буфер 1,2,3,4,5 Запись слева 0 -> 1,2,3,4,5 на выходе должны получить 0,1,2,3,4. Запись справа 6 -> 1,2,3,4,5 на выходе должны получить 2,3,4,5,6 Вот такая должна быть реализация. Исключения Переполнения быть не должно.

Вот обновленная реализация кольцевого буфера с автоматической заменой элементов при заполнении:

csharp

using System;

using System.Collections.Generic;

using System.Threading;

 

public class ThreadSafeCircularBuffer<T>

{

    private readonly T[] buffer;

    private int start = 0;

    private int count = 0;

    private readonly int capacity;

    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

   

    public ThreadSafeCircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

       

        capacity = size;

        buffer = new T[size];

    }

 

    // Запись слева с вытеснением справа

    public void EnqueueLeft(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int index = (start - 1 + capacity) % capacity;

           

            // Если буфер полон, сдвигаем начало

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[index] = item;

            start = index;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Запись справа с вытеснением слева

    public void EnqueueRight(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int end = (start + count) % capacity;

           

            // Если буфер полон, сдвигаем конец

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[end] = item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение слева

    public T DequeueLeft()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            T item = buffer[start];

            start = (start + 1) % capacity;

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение справа

    public T DequeueRight()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            int index = (start + count - 1) % capacity;

            T item = buffer[index];

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Текущая длина буфера

    public int Count

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

 

    // Максимальная вместимость

    public int Capacity => capacity;

 

    // Проверка на пустоту

    public bool IsEmpty

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count == 0;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

}

Примеры использования

csharp

// Пример 1: Базовая работа с вытеснением

var buffer = new ThreadSafeCircularBuffer<int>(5);

 

// Заполняем буфер

for (int i = 1; i <= 5; i++)

    buffer.EnqueueRight(i); // 1,2,3,4,5

 

// Запись слева с вытеснением

buffer.EnqueueLeft(0); // 0,1,2,3,4

 

// Запись справа с вытеснением

buffer.EnqueueRight(6); // 2,3,4,5,6

 

// Пример 2: Последовательная запись

var buffer2 = new ThreadSafeCircularBuffer<string>(3);

 

buffer2.EnqueueRight("A"); // A

buffer2.EnqueueRight("B"); // A,B

buffer2.EnqueueRight("C"); // A,B,C

buffer2.EnqueueRight("D"); //

Может быть я плохо искал. Но в Вашей реализации нет возможности итерации элементов. Мне еще нужна возможность - итерация элементов FromLeft - итерация элементов FromRight

Давайте добавим итераторы для обхода буфера слева направо и справа налево.

csharp

using System;

using System.Collections.Generic;

using System.Threading;

 

public class ThreadSafeCircularBuffer<T>

{

    private readonly T[] buffer;

    private int start = 0;

    private int count = 0;

    private readonly int capacity;

    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

   

    public ThreadSafeCircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

       

        capacity = size;

        buffer = new T[size];

    }

 

    // Запись слева с вытеснением справа

    public void EnqueueLeft(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int index = (start - 1 + capacity) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[index] = item;

            start = index;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Запись справа с вытеснением слева

    public void EnqueueRight(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int end = (start + count) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[end] = item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Итератор слева направо

    public IEnumerator<T> IteratorFromLeft()

    {

        _lock.EnterReadLock();

        try

        {

            int current = start;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current + 1) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Итератор справа налево

    public IEnumerator<T> IteratorFromRight()

    {

        _lock.EnterReadLock();

        try

        {

            int current = (start + count - 1) % capacity;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current - 1 + capacity) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Остальные методы остаются без изменений...

}

Примеры использования итераторов

csharp

var buffer = new ThreadSafeCircularBuffer<int>(5);

 

// Заполняем буфер

buffer.EnqueueRight(1);

buffer.EnqueueRight(2);

buffer.EnqueueRight(3);

buffer.EnqueueRight(4);

buffer.EnqueueRight(5);

 

// Итерация слева направо

Console.WriteLine("Итерация слева направо:");

foreach (var item in buffer.IteratorFromLeft())

{

    Console.Write(item + " "); // Выведет: 1 2 3 4 5

}

 

// Итерация справа налево

Console.WriteLine("\nИтерация справа налево:");

foreach (var item in buffer.IteratorFromRight())

{

    Console.Write(item + " "); // Выведет: 5 4 3 2 1

}

 

// Пример с вытеснением

buffer.EnqueueLeft(0); // 0,1,2,3,4

Console.WriteLine("\nПосле записи слева:");

foreach (var item in buffer.IteratorFromLeft())

{

    Console.Write(item + " "); // Выведет: 0 1 2 3 4

}

 

buffer.EnqueueRight(6); // 2,3,4,5,6

Console.WriteLine("\nПосле записи справа:");

foreach (var item in buffer.IteratorFromLeft())

{

    Console.Write(item + " "); // Выведет: 2 3 4 5 6

}

сделай пож-ста полный текст кода, а то код длинный не удобно вставлять в разные места, можно ошибиться при вставках. Выложи пож-ста полный код

Вот полный код реализации кольцевого буфера с итераторами:

csharp

using System;

using System.Collections.Generic;

using System.Threading;

 

public class ThreadSafeCircularBuffer<T>

{

    private readonly T[] buffer;

    private int start = 0;

    private int count = 0;

    private readonly int capacity;

    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

   

    // Конструктор

    public ThreadSafeCircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

       

        capacity = size;

        buffer = new T[size];

    }

 

    // Запись слева с вытеснением справа

    public void EnqueueLeft(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int index = (start - 1 + capacity) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[index] = item;

            start = index;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Запись справа с вытеснением слева

    public void EnqueueRight(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int end = (start + count) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[end] = item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение слева

    public T DequeueLeft()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            T item = buffer[start];

            start = (start + 1) % capacity;

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение справа

    public T DequeueRight()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            int index = (start + count - 1) % capacity;

            T item = buffer[index];

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Итератор слева направо

    public IEnumerator<T> IteratorFromLeft()

    {

        _lock.EnterReadLock();

        try

        {

            int current = start;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current + 1) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Итератор справа налево

    public IEnumerator<T> IteratorFromRight()

    {

        _lock.EnterReadLock();

        try

        {

            int current = (start + count - 1) % capacity;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current - 1 + capacity) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Текущая длина буфера

    public int Count

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

 

    // Максимальная вместимость

    public int Capacity => capacity;

 

    // Проверка на пустоту

    public bool IsEmpty

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count == 0;

            }

            finally

            {

Вот на этом месте код оборвался - видимо стоит ограничение на кол-во строк при выводе страницы { get { _lock.EnterReadLock(); try { return count == 0; } finally { ------------------------ Продолжи пож-ста с места // Максимальная вместимость public int Capacity => capacity; // Проверка на пустоту public bool IsEmpty

Вот полный код с продолжением:

csharp

using System;

using System.Collections.Generic;

using System.Threading;

 

public class ThreadSafeCircularBuffer<T>

{

    private readonly T[] buffer;

    private int start = 0;

    private int count = 0;

    private readonly int capacity;

    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

   

    // Конструктор

    public ThreadSafeCircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

       

        capacity = size;

        buffer = new T[size];

    }

 

    // Запись слева с вытеснением справа

    public void EnqueueLeft(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int index = (start - 1 + capacity) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[index] = item;

            start = index;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Запись справа с вытеснением слева

    public void EnqueueRight(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int end = (start + count) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[end] = item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение слева

    public T DequeueLeft()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            T item = buffer[start];

            start = (start + 1) % capacity;

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение справа

    public T DequeueRight()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            int index = (start + count - 1) % capacity;

            T item = buffer[index];

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Итератор слева направо

    public IEnumerator<T> IteratorFromLeft()

    {

        _lock.EnterReadLock();

        try

        {

            int current = start;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current + 1) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Итератор справа налево

    public IEnumerator<T> IteratorFromRight()

    {

        _lock.EnterReadLock();

        try

        {

            int current = (start + count - 1) % capacity;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current - 1 + capacity) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Текущая длина буфера

    public int Count

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

 

    // Максимальная вместимость

    public int Capacity => capacity;

 

    // Проверка на пустоту

    public bool IsEmpty

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count == 0;

            }

            finally

            {

                _lock.ExitRead

// Максимальная вместимость public int Capacity => capacity; // Проверка на пустоту public bool IsEmpty { get { _lock.EnterReadLock(); try { return count == 0; } finally { _lock.ExitRead -------- Выложи код с этого места, код оборвался // Максимальная вместимость public int Capacity => capacity; // Проверка на пустоту public bool IsEmpty {

Вот полное завершение класса:

csharp

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

 

    // Проверка на заполненность

    public bool IsFull

    {

        get

        {

            _lock.EnterReadLock();

            try

            {

                return count == capacity;

            }

            finally

            {

                _lock.ExitReadLock();

            }

        }

    }

 

    // Очистка буфера

    public void Clear()

    {

        _lock.EnterWriteLock();

        try

        {

            start = 0;

            count = 0;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Получение элемента по индексу

    public T Peek(int index)

    {

        _lock.EnterReadLock();

        try

        {

            if (index < 0 || index >= count)

                throw new IndexOutOfRangeException();

 

            return buffer[(start + index) % capacity];

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

}

Теперь класс полностью завершен и включает:

  • Все методы работы с буфером
  • Проверки на пустоту и заполненность
  • Очистку буфера
  • Получение элемента по индексу
  • Полную синхронизацию доступа через ReaderWriterLockSlim

Вы можете скопировать весь код целиком и использовать его в своем проекте.

GetAllFromLeft(IEnumerable[] ) GetAllFromRight(IEnumerable[]) TryGetAllFromLeft(IEnumerable[]) TryGetAllFromRight(IEnumerable[]) Если в реализации таких методов, то необходимо их реализовать

Вот обновленная версия класса с методами массовой выборки элементов:

csharp

using System;

using System.Collections.Generic;

using System.Threading;

 

public class ThreadSafeCircularBuffer<T>

{

    private readonly T[] buffer;

    private int start = 0;

    private int count = 0;

    private readonly int capacity;

    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

   

    // Конструктор

    public ThreadSafeCircularBuffer(int size)

    {

        if (size <= 0)

            throw new ArgumentException("Размер буфера должен быть положительным");

       

        capacity = size;

        buffer = new T[size];

    }

 

    // Запись слева с вытеснением справа

    public void EnqueueLeft(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int index = (start - 1 + capacity) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[index] = item;

            start = index;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Запись справа с вытеснением слева

    public void EnqueueRight(T item)

    {

        _lock.EnterWriteLock();

        try

        {

            int end = (start + count) % capacity;

           

            if (count == capacity)

                start = (start + 1) % capacity;

            else

                count++;

           

            buffer[end] = item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение слева

    public T DequeueLeft()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            T item = buffer[start];

            start = (start + 1) % capacity;

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Чтение справа

    public T DequeueRight()

    {

        _lock.EnterWriteLock();

        try

        {

            if (count == 0)

                throw new InvalidOperationException("Буфер пуст");

 

            int index = (start + count - 1) % capacity;

            T item = buffer[index];

            count--;

            return item;

        }

        finally

        {

            _lock.ExitWriteLock();

        }

    }

 

    // Итератор слева направо

    public IEnumerator<T> IteratorFromLeft()

    {

        _lock.EnterReadLock();

        try

        {

            int current = start;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current + 1) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Итератор справа налево

    public IEnumerator<T> IteratorFromRight()

    {

        _lock.EnterReadLock();

        try

        {

            int current = (start + count - 1) % capacity;

            int elementsRead = 0;

           

            while (elementsRead < count)

            {

                yield return buffer[current];

                current = (current - 1 + capacity) % capacity;

                elementsRead++;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Получение всех элементов слева

    public void GetAllFromLeft(List<T> result)

    {

        _lock.EnterReadLock();

        try

        {

            result.Clear();

            int current = start;

            for (int i = 0; i < count; i++)

            {

                result.Add(buffer[current]);

                current = (current + 1) % capacity;

            }

        }

        finally

        {

            _lock.ExitReadLock();

        }

    }

 

    // Получение всех элементов справа

    public void GetAllFromRight(List<

Вот на этом коде обрывается вывод кода, маленкая страница // Получение всех элементов слева public void GetAllFromLeft(List<T> result) { _lock.EnterReadLock(); try { result.Clear(); int current = start; for (int i = 0; i < count; i++) { result.Add(buffer[current]); current = (current + 1) % capacity; } } finally { _lock.ExitReadLock(); } } Напиши только эти четыре метода. GetAllFrom Также можешь еще два метода добавить ReSizeFromLeft(int newsize) ReSizeFromRight(int newsize)

Вот реализация запрошенных методов:

csharp

// Получение всех элементов слева

public void GetAllFromLeft(List<T> result)

{

    _lock.EnterReadLock();

    try

    {

        result.Clear();

        int current = start;

        for (int i = 0; i < count; i++)

        {

            result.Add(buffer[current]);

            current = (current + 1) % capacity;

        }

    }

    finally

    {

        _lock.ExitReadLock();

    }

}

 

// Получение всех элементов справа

public void GetAllFromRight(List<T> result)

{

    _lock.EnterReadLock();

    try

    {

        result.Clear();

        int current = (start + count - 1) % capacity;

        for (int i = 0; i < count; i++)

        {

            result.Add(buffer[current]);

            current = (current - 1 + capacity) % capacity;

        }

    }

    finally

    {

        _lock.ExitReadLock();

    }

}

 

// Попытка получения всех элементов слева (без исключения)

public bool TryGetAllFromLeft(List<T> result)

{

    _lock.EnterReadLock();

    try

    {

        if (count == 0)

            return false;

       

        result.Clear();

        int current = start;

        for (int i = 0; i < count; i++)

        {

            result.Add(buffer[current]);

            current = (current + 1) % capacity;

        }

        return true;

    }

    finally

    {

        _lock.ExitReadLock();

    }

}

 

// Попытка получения всех элементов справа (без исключения)

public bool TryGetAllFromRight(List<T> result)

{

    _lock.EnterReadLock();

    try

    {

        if (count == 0)

            return false;

       

        result.Clear();

        int current = (start + count - 1) % capacity;

        for (int i = 0; i < count; i++)

        {

            result.Add(buffer[current]);

            current = (current - 1 + capacity) % capacity;

        }

        return true;

    }

    finally

    {

        _lock.ExitReadLock();

    }

}

 

// Изменение размера буфера с сохранением элементов слева

public void ReSizeFromLeft(int newSize)

{

    if (newSize <= 0)

        throw new ArgumentException("Размер должен быть положительным");

       

    _lock.EnterWriteLock();

    try

    {

        T[] newBuffer = new T[newSize];

        int elementsToCopy = Math.Min(count, newSize);

       

        // Копируем элементы слева

        int srcIndex = start;

        for (int i = 0; i < elementsToCopy; i++)

        {

            newBuffer[i] = buffer[srcIndex];

            srcIndex = (srcIndex + 1) % capacity;

        }

       

        buffer = newBuffer;

        start = 0;

        count = elementsToCopy;

        capacity = newSize;

    }

    finally

    {

        _lock.ExitWriteLock();

    }

}

 

// Изменение размера буфера с сохранением элементов справа

public void ReSizeFromRight(int newSize)

{

    if (newSize <= 0)

        throw new ArgumentException("Размер должен быть положительным");

       

    _lock.EnterWriteLock();

    try

    {

        T[] newBuffer = new T[newSize];

        int elementsToCopy = Math.Min(count, newSize);

       

        // Вычисляем новый start для нового буфера

        int newStart = newSize - elementsToCopy;

        int srcIndex = (start + count - 1) % capacity;

       

        // Копируем элементы справа

        for (int i = newStart; i < newStart + elementsToCopy; i++)

        {

            newBuffer[i] = buffer[srcIndex];

            srcIndex = (srcIndex - 1 + capacity) % capacity;

        }

       

        buffer = newBuffer;

        start = newStart;

        count = elementsToCopy;

        capacity = newSize;

    }

    finally

    {

В контексте нашего CircularBuffer уместно ли реализоваить shifts (сдвиги) - с вытеснением - с зацикливанием ?

Давайте рассмотрим, как можно реализовать сдвиги в кольцевом буфере:

Сдвиги с вытеснением

При таком сдвиге элементы смещаются на заданное количество позиций, а вытесненные элементы удаляются.

Сдвиги с зацикливанием

При таком сдвиге элементы перемещаются циклически, без потери данных.

Вот реализация этих методов:

csharp

// Сдвиг влево с вытеснением

public void ShiftLeft(int positions)

{

    _lock.EnterWriteLock();

    try

    {

        if (positions <= 0) return;

        positions %= capacity;

       

        start = (start + positions) % capacity;

        count = Math.Min(count - positions, capacity);

    }

    finally

    {

        _lock.ExitWriteLock();

    }

}

 

// Сдвиг вправо с вытеснением

public void ShiftRight(int positions)

{

    _lock.EnterWriteLock();

    try

    {

        if (positions <= 0) return;

        positions %= capacity;

       

        start = (start - positions + capacity) % capacity;

        count = Math.Min(count - positions, capacity);

    }

    finally

    {

        _lock.ExitWriteLock();

    }

}

 

// Циклический сдвиг влево

public void RotateLeft(int positions)

{

    _lock.EnterWriteLock();

    try

    {

        if (positions <= 0 || count == 0) return;

        positions %= count;

       

        start = (start + positions) % capacity;

    }

    finally

    {

        _lock.ExitWriteLock();

    }

}

 

// Циклический сдвиг вправо

public void RotateRight(int positions)

{

    _lock.EnterWriteLock();

    try

    {

        if (positions <= 0 || count == 0) return;

        positions %= count;

       

        start = (start - positions + capacity) % capacity;

    }

    finally

    {

        _lock.ExitWriteLock();

    }

}

Объяснение методов:

1.  ShiftLeft/ShiftRight (с вытеснением):

  • Сдвигают элементы на заданное количество позиций
  • Вытесненные элементы удаляются из буфера
  • Размер буфера уменьшается на количество сдвигов

2.  RotateLeft/RotateRight (с зацикливанием):

  • Перемещают элементы циклически
  • Ни один элемент не теряется
  • Просто изменяется точка начала буфера

Примеры использования:

csharp

var buffer = new ThreadSafeCircularBuffer<int>(5);

buffer.EnqueueRight(1);

buffer.EnqueueRight(2);

buffer.EnqueueRight(3);

buffer.EnqueueRight(4);

buffer.EnqueueRight(5);

 

// Сдвиг влево на 2 позиции с вытеснением

buffer.ShiftLeft(2); // Буфер станет: 3,4,5

 

// Циклический сдвиг вправо на 1 позицию

buffer.RotateRight(1); // Буфер станет: 5,3,4

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

 

Комментариев нет:

Отправить комментарий