I have a form with a control on it to display some custom objects. In the form I subscribe to an event AddObject that adds objects to a ToAdd List as they come in from the server. I setup a timer to run every 10 seconds to copy the objects from the ToAdd List to the Display List (it was more efficient adding the items in bulk to the control than 1 at a time as they came in), which is bound to a control on my form, then I clear the ToAdd List. Is it safe to have the lock inside of the BeginInvoke? Is there a better way of doing this?
private System.Threading.Timer aTimer;
private readonly Object sync = new Object();
List<object> ToAdd = new List<object();
List<object> Display = new List<object();
private void Init()
{
TimerCallback tcb = IntermittentProcessMessages;
aTimer = new System.Threading.Timer(tcb, null, 1000, 100);
Server.MessageReceived += AddObject;
}
private void AddObject(object t)
{
lock (sync)
{
try
{
ToAdd.Add(t);
}
finally() {}
}
}
private void IntermittentProcessMessages(object source)
{
try
{
if (this.IsHandleCreated == false)
{
return;
}
this.BeginInvoke((Action)delegate()
{
lock (sync)
{
if (ToAdd.Count > 0)
{
ToAdd.ForEach(f => Display.Add(f));
ToAdd.Clear();
}
}
}
}
finally(){}
}
Yes it is safe. Technically the lock is not in the
BeginInvoke, but in the anonymous function that is is created from thedelegate.Some notes:
List<T>has anAddRangemethod that is more efficient than multipleAdd.Use it like
Display.AddRange(ToAdd);IntermittentProcessMessagesis not covered by the try-catch since theBeginInvokereturns immediately.