Skip to main content
 首页 » 编程设计

c#之如何控制多个线程对对象集合的访问

2024年01月13日27kevingrace

我正在编写一个显示对象列表的应用程序,用户可以选择这些对象,然后通过 PropertyGrid 控件查看和编辑其属性。通过使用辅助线程从文件中提取信息的耗时过程会填充对象的属性。但我也希望允许用户在提取过程进行时继续查看其他对象。

阅读对 my previous 的回复后关于SO的问题。这听起来像是因为提取过程正在写入的属性不会与用户可通过属性网格编辑的属性相交我不应该对同时编辑对象的两个线程有​​问题。尽管用户可能会看到不正确的值,如果他们非常不幸并且属性网格最终在非原子写入的中间读取对象。

但是,我仍然想知道如何设置它以防止用户编辑或查看正在提取的对象。我对多线程非常陌生,但我读过的大多数示例都显示了一个单独的 token 对象被创建用于锁定对感兴趣的实际对象的访问。我的另一个答案previous question确认创建一个像这样专门用于锁定的单独对象是典型的。

那么现在我想知道在我有大量对象的情况下如何处理这个问题?我想创建锁以防止属性网格显示用户选择的对象(如果当前正在将其提取到)。

我是否需要创建一个单独的锁对象集合并与我的真实集合保持同步?因此,如果从我的主集合中添加或删除一个对象,我必须从我的锁集合中添加或删除锁对象吗?

我是否锁定到实际对象而不是创建单独的 token 锁定对象?

如何向对象添加“IsBeingExtracted” bool 属性,属性网格可以检查该对象是否正在被写入?这将在提取过程的开始和结束时设置。

或者在某处引用当前(如果有)对象的静态字段如何,该对象当前被提取到。然后属性网格可以检查它被要求显示的最新对象是否不是这个静态字段引用的对象?如果有多个提取线程,这当然行不通。

执行此操作的最佳/正确方法是什么?就个人而言,我最喜欢 bool 属性选项,但想知道其他真正知道自己在做什么的人是怎么想的。

请您参考如下方法:

难道你不能让包含对象的集合成为SynchronizedCollection<T>吗? ?它将确保一次只有一个线程可以添加或访问对象。然后,不必担心如何同步访问每个对象的属性,在对象被填充之前不要将其添加到集合中。

像这样:

private readonly ICollection<Item> Items = new SynchronizedCollection<Item>(); 
 
// Run this on the background thread. 
public void PopulateItems() 
{ 
    using (var file = File.OpenRead("BigFile.txt")) 
    using (var reader = new StreamReader(file)) 
    { 
        while (!reader.EndOfStream) 
        { 
            var item = new Item(); 
            PopulateItem(item); 
            Items.Add(item); 
        } 
    } 
} 
 
public void PopulateItem(Item item) 
{ 
    // Do time-consuming work. 
} 

属性网格可以愉快地对对象做任何它想做的事情,因为当它出现在列表中时,提取线程已经完成了它。无需显式锁定。