Информация об изменениях

Сообщение Вопрос про неблокирующий буфер от 28.04.2015 19:37

Изменено 28.04.2015 19:38 SergASh

Привет всем!

Имеем класс 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
  {
[cut]
    #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
[/cut]

    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();
    }
  }
Вопрос про неблокирующий буфер
Привет всем!

Имеем класс 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; }
}