Tom said:
Well, I might change the design a bit and instead of an array, you could have
a collection that monitors the contents (maybe a background thread), removing
and disposing anything older then a certain amount.
To elaborate on Tom's suggestion (which IMHO is a good way to go):
Instead of the array, use a Queue<T> to manage the collection. You can
call ToArray() on the queue in order to do whatever processing is
necessary to make existing messages visible to nearby devices. The key
of using Queue<T> is that it's implemented efficiently, as a circular
buffer, and you can pull message instances from the front of the queue
until the first message available is young enough to be kept.
Use a dedicated thread to deal with removing messages at the appropriate
time, or just check the queue every so often (e.g. once a second).
For example (warning: uncompiled, untested):
// Keep the messages ten seconds
const TimeSpan ktsTimeToLive = new TimeSpan(0, 0, 10);
struct Message
{
public DateTime Expires { get; private set; }
public string Message { get; private set; }
public Message(String strMessage)
{
Message = _strMessage;
Expires = DateTime.Now + ktsTimeToLive;
}
}
class MessageManager
{
private Queue<Message> _qmsg = new Queue<Message>();
private readonly object _objLock = new object();
private bool _fDone;
private bool _fStarted;
public void Start()
{
lock (_objLock)
{
if (_fStarted)
{
throw new InvalidOperationException("Manager is already
started");
}
new Thread(_ExpireMessages).Start();
_fStarted = true;
_fDone = false;
}
}
public void Stop()
{
lock (_objLock)
{
_fDone = true;
Monitor.Pulse(_objLock);
}
}
public void Add(Message msg)
{
lock (_objLock)
{
if (!_fStarted)
{
throw new InvalidOperationException("Manager has not been
started");
}
if (_fDone)
{
throw new InvalidOperationException("Manager has been stopped");
}
_qmsg.Enqueue(msg);
// Only need to wake up monitoring thread if the queue
// was empty. Otherwise, it will wake up on its own.
if (_qmsg.Count == 1)
{
Monitor.Pulse(_objLock);
}
}
}
public Message[] Messages
{
get { lock (_objLock) return _qmsg.ToArray(); }
}
private void _ExpireMessages()
{
lock (_objLock)
{
while (!_fDone)
{
// Remove any messages that have expired
while (_qmsg.Count > 0 &&
_qmsg.Peek().Expires < DateTime.Now)
{
_qmsg.Dequeue();
}
if (_qmsg.Count > 0)
{
// Wait until the next expiration time
Monitor.Wait(_objLock, _qmsg.Peek().Expires - DateTime.Now);
}
else
{
// Wait until the queue has contents again
Monitor.Wait(_objLock);
}
}
_fStarted = false;
}
}
}
Note that the above assumes that all messages expire at the same amount
of time after they are created. If different messages can have
different amounts of time they stay alive, then you'll either need to
use an ordered list instead of a queue, or you'll need a different queue
for each time delta possible (only practical if there are only a small
number of different deltas possible).
Pete