在BeginInvoke调用中使用lock()安全吗?
本文关键字:安全 lock BeginInvoke 调用 | 更新日期: 2023-09-27 18:10:21
我有一个带有控件的表单来显示一些自定义对象。在表单中,我订阅了一个事件AddObject,当对象从服务器传入时,它将对象添加到ToAdd List中。我设置了一个计时器,每10秒运行一次,将对象从ToAdd List复制到Display List(将项目批量添加到控件中比每次添加1个项目更有效),这与我的窗体上的控件绑定在一起,然后清除ToAdd List。把锁放在BeginInvoke里面安全吗?有更好的方法吗?
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(){}
}
是安全的。从技术上讲,锁不在BeginInvoke
中,而是在从delegate
创建的匿名函数中。
一些注意事项:
-
List<T>
有一个AddRange
方法,比多个Add
更有效。
像Display.AddRange(ToAdd);
一样使用 -
IntermittentProcessMessages
中的委托不被try-catch覆盖,因为BeginInvoke
立即返回。