【问题标题】:Need an explanation on Lifetime of Objects Created in a Thread需要关于线程中创建的对象的生命周期的解释
【发布时间】:2012-04-14 13:32:56
【问题描述】:

我有一个绑定到 BindingList 的 DevExpress GridControl。

我试图从一个线程中修改 BindingList,这引发了一个异常,我用谷歌搜索了它并找到了以下解释:

此问题与 XtraGrid 没有直接关系。不幸的是,您不能在后台线程中更改网格的数据源,因为这会导致很多同步问题。 XtraGrid 可能会在您的后台线程更改它的同时对底层数据源执行一些操作。在这种情况下,网格稍后可能会收到更改通知,并会尝试从数据源更新行,这将导致上述问题。很多情况下可能会出现这个问题。例如,当用户编辑数据、对其进行分组或 XtraGrid 尝试重新计算摘要时。此问题的唯一解决方案是在后台线程中更改 Grid 的 DataSource 引用(注意:您需要使用 Invoke 方法来实现它)。换句话说,在后台线程中,您应该使用 DataSource 的本地副本,并在必要时将其克隆传递给 Grid 的 DataSource。在随附的示例中,您将找到一个演示此方法的示例项目。

我尝试了它所说的,结果是这样的:

proxyWorker = new Thread(() =>
{
    //Clone the datasource into the thread
    BindingList<Proxy> newList = new BindingList<Proxy>(proxies);

    //Set the proxy source to the cloned datasource in the thread
    gcProxies.BeginInvoke(new MethodInvoker(delegate { gcProxies.DataSource = newList; }));

   //Logic here
});

proxyWorker.Name = "proxyTester";

proxyWorker.Start();

它有效,但我不明白线程结束后数据源会发生什么? newList不是被销毁了吗?

我的想法是最后我会重新克隆 newList 并将其设置回proxies(原始数据源)

【问题讨论】:

  • 请输入一个概括您问题的标题。
  • 已修复,抱歉忘记正确设置。

标签: c# winforms multithreading object-lifetime


【解决方案1】:

我认为您的困惑源于您认为 .NET 对象与创建它的线程相关联。情况并非如此,进程中的所有线程共享同一个 GC 堆。在一个线程中创建的 List 对象与另一个线程中的 List 没有什么不同,它不会以任何方式使创建它的线程保持活动状态。

什么线程的一个问题是有很多类不是线程安全的。任何 UI 组件肯定都是这种情况。您不能做的是从另一个线程分配此类对象的属性,而该属性值也可以在 UI 线程中使用。 UI 组件的几乎所有属性都有这个限制。数据绑定特别麻烦,因为属性分配不是直接可见的。您只设置 DataSource,而不是绑定设置的所有其他属性。使用 Control.BeginInvoke 或 Dispatcher.BeginInvoke 可确保在创建控件的同一线程中设置属性值,从而解决线程安全问题。

【讨论】:

  • 我最后所做的是将绑定的对象克隆到线程中,最后将其克隆回原始源。效果很好!
【解决方案2】:

这就是“一对一”的 C# 垃圾回收

new list 继续存在,通过gcProxies.DataSource 引用。

直到您用完对该列表的引用为止。

除非您正在访问跨线程或在一个线程中创建并在另一个线程中使用的“列表”存在任何特定的“跨线程”问题 - 一切都会很好。
在这里,您只是在初始化并且除了通过 DataSource 之外再也不会使用它,所以一切都很好。

希望对你有帮助

编辑:回答 cmets,我稍微简化一下

您偶然创建对象的线程与对象的“生命周期”无关 - 即线程不拥有该对象。应用程序域可以(超出范围),但您可以“跨越”线程边界或做任何您想做的事情 - 但您“只需要”同步您的代码/对象。

【讨论】:

  • 我确实在程序的另一部分再次使用它,但它会引发错误。最后我应该将克隆的数据源复制回原来的位置吗?
  • @TheGateKeeper - 你的问题原来是关于引用和引用类型的,请意识到这一点。
  • @TheGateKeeper 最后?不,您应该正确解决您的问题,以及“为什么”。正如 Henk 所说,您应该重新措辞并添加更多关于错误的数据,您在哪里访问它等。基本上您需要同步 - 或者如果在其他地方使用,则再次“调用”(如果可能,并不总是那么简单)
  • 哦,这太令人困惑了... GridControl 怎么仍然引用我在线程中创建的对象?只要引用被持有,线程是否保持活动状态?
猜你喜欢
  • 1970-01-01
  • 2011-04-11
  • 2016-07-31
  • 2021-12-22
  • 2011-02-19
  • 2014-12-22
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
相关资源
最近更新 更多