0

在过去的 4 年里,我一直在使用 c# 代码,但最近我经历了一个我从未经历过的场景。我有一个该死的项目来解决“索引超出范围错误”。代码看起来很疯狂,所有不必要的东西都在那里,但它已经投入生产了 3 年,我只需要解决这个问题。来到问题所在。

class FilterCondition
{
   .....
   public string DataSetName {get; set;}
   public bool IsFilterMatch()
   {
      //somecode here
      Dataset dsDataSet = FilterDataSources.GetDataSource(DataSetName); // Static class and Static collection
      var filter = "columnname filtername"
      //some code here
      ds.defaultview.filter= filter;
      var isvalid = ds.defaultView.rowcount > 0? true : false;
      return isValid;
   }
}

// from a out side function they put this in a parallel loop

Parallel.ForEach()
{
   // at some point its calling
   item.IsFiltermatch();
}   

当我调试时,dsDataSet我看到dsDataSet修改了我的多个线程。这就是为什么会发生竞争条件并且它无法应用过滤器并且由于索引超出范围而失败。

我的问题是,我的方法是非静态和线程安全的,那么这种竞争条件是如何发生的,因为dsDataset它是我的成员函数内的局部变量。奇怪,我怀疑与 Parallel.Foreach 有关。

当我在那里放一个普通锁时,问题得到了解决,为此我也没有答案。为什么要锁定非静态成员函数?

谁能给我一个答案。我是小组的新手。如果我在问题中遗漏任何内容,请告诉我。由于那里的客户限制,我无法复制整个代码。谢谢阅读。

4

3 回答 3

3

因为它不是线程安全的。
您正在从多个线程访问静态集合。

您对局部变量有误解。尽管变量是本地的,但它指向的对象却不是。

你应该做的是在你读写静态集合的地方加一个锁。

于 2013-07-27T17:40:38.360 回答
1

问题:问题出在这个调用中

FilterDataSources.GetDataSource(DataSetName);

在此方法中,您正在写入共享资源。

解决方案:

您需要知道这里正在写入哪个字段,并且需要对其进行锁定。

注意:如果您可以发布上述方法的代码,我们将能够更好地帮助您。

于 2013-07-27T17:47:39.193 回答
0

我相信这是因为特定的(非无状态,非线程安全等)实现FilterDataSources.GetDataSource(DataSetName),即使通过方法调用,这似乎是一个静态方法。这个方法可以做不同的事情,甚至返回缓存DataSet的实例,拦截对数据集项目的调用,返回一个 DataSet 包装器,所以你使用的是包装器而不是数据集,所以可以有很多东西。如果你想很好,让我们说导致这种情况的“确切的代码行”,请向我们展示GetDataSource()方法的实现和类的所有底层静态上下文(静态字段、构造函数、如果存在FilterDataSource则调用的其他静态方法......)GetDataSource()

于 2013-07-27T17:40:47.847 回答