需要解释在线程中创建的对象的生命周期

时间:2012-04-14 13:32:57

标签: c# winforms multithreading object-lifetime

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

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

此问题与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(原始数据源)

2 个答案:

答案 0 :(得分:3)

我认为您的困惑源于您认为.NET对象与创建它的线程相关联的事实。情况并非如此,进程中的所有线程共享相同的GC堆。列表&lt;&gt;在一个线程中创建的对象与List&lt;&gt;没有区别在另一个方面,它不会以任何方式保持创建它的线程。

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

答案 1 :(得分:2)

这是'一对一'的C#垃圾收集

new list依然存在,通过gcProxies.DataSource引用。

在你用完该列表的引用之前,你很好。

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

希望这会有所帮助

编辑:回答评论,我简化了一下

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