Вопрос про неблокирующий буфер
От: SergASh  
Дата: 28.04.15 19:37
Оценка:
Привет всем!

Имеем класс MessageGateway, скелет которого ниже. Идея в том, что из разных потоков
вызывается MessageGateway.Instance.ConveyMessage( "что-то там..." ), сообщению присваивается
порядковый номер и метка времени. После этого сообщение передается дальше по конвейеру (здесь не показано).

Из другого потока код может попросить отдать ему все (GetAllMessages) или часть сообщений (GetRecentMessages).

Требуется:
1. В любой момент времени хранить не более N сообщений.
2. Не хранить сообщения, добавленные ранее, чем M секунд назад.
3. Потокобезопасно отдавать все актуальные сообщения (GetAllMessages)
4. Потокобезопасно отдавать сообщения с порядковым номером большим некоторого произвольного числа (GetRecentMessages)
5. Не блокировать поток при вызове ConveyMessage.
6. Не копировать сообщения в GetAllMessages и в GetRecentMessages.
7. Неохотно, но готов смириться с блокировкой при вызове GetAllMessages и GetRecentMessages, но они не должны блокировать добавление новых сообщений.

1 решается кольцевым буфером. 2-4 можно решить обвешав все локами.

Насколько я понимаю, обычный лок ничем не поможет, если надо вернуть перечислитель.
Тут надо либо копировать всю последовательность, то есть прости-прощай №6, либо вызывать Monitor.Exit из метода Dispose перечислителя.
В последнем случае если про Dispose забудут, то все ляжет.

Как сделать №5 пока не представляю.

  Скрытый текст
public class MessageGateway
{
  #region Singleton
  private MessageGateway()
  {}
  public static MessageGateway Instance
  {
    get { return instance__.Value; }
  }
  private static readonly Lazy<MessageGateway> instance__ = new Lazy<MessageGateway>( () => new MessageGateway() );
  #endregion // Singleton

  private long identity_;

  private static readonly long maximumMessagesStored__ = 1000;
  private static readonly TimeSpan maximumMessageRetainPeriod__ = TimeSpan.FromSeconds( 600 );

  private void Enqueue( Message message )
  {
    throw new NotImplementedException();
  }

  public void ConveyMessage( string message )
  {
    var msg = new Message
              {
                MessageId = Interlocked.Increment( ref identity_ ),
                TimeStamp = DateTime.UtcNow,
                Text = message
              };
    Enqueue( msg );
  }

  public IEnumerable<Message> GetAllMessages()
  {
    throw new NotImplementedException();
  }
  public IEnumerable<Message> GetRecentMessages( long startingFromId )
  {
    throw new NotImplementedException();
  }
}
public class Message
{
  public long MessageId { get; set; }
  public DateTime TimeStamp { get; set; }
  public string Text { get; set; }
}
Отредактировано 28.04.2015 19:38 SergASh . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.