Привет всем!
Имеем класс 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; }
}
|
| |