Связанный список будет работать, и вряд ли его блокировка (если все сделано правильно) приведет к снижению производительности. Возможно, вам было бы гораздо лучше использовать ConcurrentQueue . Это потокобезопасно, так что вам не нужно делать никаких явных блокировок.
Я бы предложил использовать System.Threading.Timer
вместо таймера Windows Forms. Обратите внимание, что вы все равно будете ограничены разрешением около 15 мс. То есть даже с интервалом таймера 1 ваши эффективные времена задержки будут в диапазоне от 15 до 25 мс, а не 1 мс. Это просто способ реализации таймеров.
Кроме того, поскольку вы хотите отложить каждый элемент на определенный период времени (который я предполагаю постоянным), вам необходимо некоторое представление о «текущем времени». Я не рекомендую использовать DateTime.Now
или любой из его вариантов, потому что время может измениться. Вместо этого я использую Stopwatch
, чтобы получить время для конкретного приложения.
Кроме того, вам понадобится способ отслеживать время выпуска элементов. Класс для хранения элемента и время его отправки. Что-то вроде:
class BufferItem
{
public string Data { get; private set; }
public TimeSpan ReleaseTime { get; private set; }
public BufferItem(string d, TimeSpan ts)
{
data = d;
ReleaseTime = ts;
}
}
Хорошо. Давайте сложим все вместе.
// the application clock
Stopwatch AppTime = Stopwatch.StartNew();
// Amount of time to delay an item
TimeSpan DelayTime = TimeSpan.FromSeconds(1.0);
ConcurrentQueue<BufferItem> ItemQueue = new ConcurrentQueue<BufferItem>();
// Timer will check items for release every 15 ms.
System.ThreadingTimer ReleaseTimer = new System.Threading.Timer(CheckRelease, null, 15, 15);
Получение предмета:
// When an item is received:
// Compute release time and add item to buffer.
var item = new BufferItem(data, AppTime.Elapsed + DelayTime);
ItemQueue.Add(item);
Таймер проц.
void CheckRelease(object state)
{
BufferItem item;
while (ItemQueue.TryPeek(out item) && item.ReleaseTime >= AppTime)
{
if (ItemQueue.TryDequeue(out item))
{
// send the item
}
}
}
Это должно работать хорошо, и у вас не должно быть проблем с параллелизмом.
Если вам не нравится этот таймер на 15 мс, который тикает все время, даже когда нет никаких элементов, вы можете сделать таймер одним выстрелом и использовать метод CheckRelease
для его повторной инициализации в следующем выпуске. время после снятия предметов. Конечно, вы также должны будете заставить код приема инициализировать его в первый раз, или когда в очереди нет элементов. Вам потребуется блокировка для синхронизации доступа к обновлению таймера.