【问题标题】:Make changes to referenced datatable in Parallel.ForEach loop在 Parallel.ForEach 循环中更改引用的数据表
【发布时间】:2014-04-01 11:52:55
【问题描述】:

我正在尝试创建一个方法,当传递带有可 ping 主机名的数据表引用时,尝试 ping 每个主机,然后根据 ping 成功更改相应列和行的值。

但是我不能在 Parallel.ForEach 方法中使用引用。有什么办法可以使这项工作?

这是我的代码:

public void checkON(ref DataTable PCS)
    {

        Parallel.ForEach(PCS.AsEnumerable(), pc =>
            {
                string loopIp = pc["Name"].ToString();
                if (PingIP(loopIp))
                {
                    DataRow[] currentpc = PCS.Select("Name = '{0}'", loopIp);
                    currentpc[0]["Online"] = "ON";
                }
                else
                {
                    DataRow[] currentpc = PCS.Select("Name = '{0}'", loopIp);
                    currentpc[0]["Online"] = "OFF";
                }
            }
        );}

【问题讨论】:

  • 那么你为什么需要ref?从您的代码中我看不到原因。此外,DataTable 是线程安全的吗? (它应该,IMO 但是......我们确定吗?)
  • @Adriano 我很确定它不是 ;p

标签: c# datatable ref parallel.foreach


【解决方案1】:

除非代码明确说明它是线程安全的,否则您应该假设它不是 - 因此访问必须同步。代码中的 ref 毫无用处。每个pc 都是一个DataRow,因此您可以直接访问它:

string loopIp;
lock(someLockObject) {
    loopIp = (string)pc["Name"];
}
string online = PingIP(loopIp) ? "ON" : "OFF";
lock(someLockObject) {
    pc["Online"] = online;
}

someLockObject所有调用者之间共享,因为您无法对线程模型做出假设:

object someLockObject = new object();
Parallel.ForEach(PCS.AsEnumerable(), pc =>
        { ... });

尤其是,您不能只锁定行,因为DataTable 不会将数据存储在行中(它会将数据存储在列中;不,真的)。

【讨论】:

  • 是的,这行得通。真的谢谢你的帮助。卡在这里好久了。初学者 :D 但我有疑问,如果你可能 :) 为什么在尝试从并行循环中的数据表中选择时,它找不到相应的行。另一个问题是实现此功能的最佳方式是什么,这样它就不会锁定 UI 线程,并且对数据表的更改将实时可见。此数据表用作 DataGridView 控件的数据源。
  • @dazgen DataTable 发布更改通知;因此,当您从其他线程进行更改时,将其主动连接是一个非常糟糕的主意......但不要冻结,与往常一样的规则:不要阻塞 UI 线程 - 并且请注意,由于Parallel.ForEach 是一个同步调用(它会阻塞直到全部完成),所以阻塞 UI 线程正是您正在做的事情。
猜你喜欢
  • 2012-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
相关资源
最近更新 更多