[英]Handling a save on a separate thread
我有一个包含(除其他事项外)一系列项目的类,这些项目需要尽可能实际地保存到磁盘中。 为了做到这一点,无论何时进行任何更改,它都会使用计时器将保存到磁盘的时间延迟半秒,如果在此半秒内发生任何进一步的更改,则会延迟计时器。 换句话说,只要半秒内没有任何更改,它将保存到磁盘。
但是,我遇到了线程问题,可以在保存过程中修改列表。 我已经提出了一种修复它的方法,但是感觉有点像破解,而且我很确定必须有一个更好的方法。
save方法在保存操作期间将线程锁定在“对象”的私有实例上,但这不会阻止列表的更新,因为它是一个单独的类,并且无法访问该私有锁。
因此,要解决此问题,我要在列表类中添加一个“即将更改”事件(无论如何,它不是一个不好的功能),并且包含类侦听此事件,并锁定相同的私有对象锁定为保存方法,但不执行任何操作。 即使列表本身不知道它包含的对象或它在做什么,这也会迫使线程等待直到保存完成才允许更新列表。
这是(严重简化的)源:
public class ItemContainer
{
private ItemList _itemList = new ItemList();
private object _padlock = new object();
public ItemContainer()
{
_itemList.ItemAdded += StartTimedSave;
_itemList.ItemAdding += (sender, e) => { lock(_padlock) { } };
}
private StartTimedSave()
{
// starts or resets a half second timer to call Save();
}
private void Save()
{
lock(_padlock)
{
foreach (object obj in _itemList)
{
// save it.
}
}
}
}
public class ItemList
{
public event EventHandler<CancelEventArgs> ItemAdding;
public event EventHandler ItemAdded;
public List<object> _list;
public void Add(object obj)
{
if (ItemAdding.RaiseWithCancel(this)) // extension method
return;
_list.Add(obj);
ItemAdded.Raise(this); // another extension method
}
}
我实际上不能让列表包含对其包含对象的引用,因为列表是一个相当笼统的类,此类对象可能包含也可能不包含。
带有空lock { }
块的事件处理程序真的是解决这个问题的方法吗? 我对允许事件处理程序干扰引发它的对象的操作的想法感到不舒服,但是我找不到更好的方法。
保存时,将列表复制到内存中并保存-这将减少数据暴露给其他线程中的更新。
为了确保线程安全,请让ItemList类创建并返回列表副本,并且ItemList类可以将内部列表锁定足够长的时间以进行复制:
public List<object> CreateListCopy()
{
List<object> result = new List<object>();
lock(_list)
{
foreach(object o in _list)
{
result.Add(o.Clone());
}
}
return result;
}
然后,将CreateListCopy()的结果保存到保存线程中。
编辑:复制项目列表时,不要忘记确保您使用的是深层复制语义,因为您不想仅复制引用; 您需要完整,完全独立的数据副本。
这什么都不做:
锁(_padlock){}
块执行期间锁定保持-没有指向锁定空块的指示。
如果所有问题都与该私有锁对象有关,则只需为其公开获取即可。 确保任何修改或读取集合的东西都将其锁定。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.