C# 为什么执行一个新线程而不创建一个新线程?

C# 为什么执行一个新线程而不创建一个新线程?,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,偶尔会有另一个线程开始执行我的代码 // the main method: // ... MatchResultsForRules(rules, results); ApplyRules(rules); //... public void MatchResultsForRules(List<Rule> Rules, List<SearchResult> Results) { foreach (Rule rule in Rules) {

偶尔会有另一个线程开始执行我的代码

// the main method:
// ...
   MatchResultsForRules(rules, results);
   ApplyRules(rules);
//...

public void MatchResultsForRules(List<Rule> Rules, List<SearchResult> Results)
{
   foreach (Rule rule in Rules)
   {
      foreach (SearchResult res in Results)
      {
         if (isResultMatchRule(rule, res))
         {
            rule.searchResults.Add(res);
         }
      }
   }
}

public void ApplyRules (List<Rule> Rules)
{
   foreach (Rule rule in Rules)
   {
      foreach(SearchResult res in rule.searchResults)
      {
         ApplyRule(rule, res);
      }
   }
}
//主要方法:
// ...
MatchResultsForRules(规则、结果);
应用规则(规则);
//...
public void MatchResultsForRules(列表规则、列表结果)
{
foreach(规则中的规则)
{
foreach(搜索结果中的搜索结果)
{
if(isResultMatchRule(rule,res))
{
规则.searchResults.Add(res);
}
}
}
}
公共无效应用程序规则(列表规则)
{
foreach(规则中的规则)
{
foreach(规则中的SearchResult res.searchResults)
{
应用规则(规则,res);
}
}
}
我知道还有另一个线程,因为一旦我看到问题发生(计算不匹配),我就打印了一个详细的日志,包括每个操作的线程Id,我看到操作顺序混乱,当然还有两个不同的线程Id

我通过操纵搜索结果本身,而不是操纵每个规则的搜索结果列表(如下所述),解决了这个问题

修复方法:

public void ApplyRules (List<Rule> rules, List<SearchResult> searchResults)
{
   foreach (Rule rule in rules)
   {
      foreach(SearchResult resFromRule in rule.searchResults)
      {
         SearchResult res = searchResults.First(
            r => r.Id.Equals(resFromRule.Id)
         );
         ApplyRule(rule, res);
      }
   }
}
public void ApplyRules(列表规则、列表搜索结果)
{
foreach(规则中的规则)
{
foreach(规则中的SearchResult resFromRule.searchResults)
{
SearchResult res=searchResults.First(
r=>r.Id.Equals(resFromRule.Id)
);
应用规则(规则,res);
}
}
}

我只是想更好地理解这个问题,以便将来不再重复这个错误。

这个答案基于这样一个假设,即
规则和
结果是共享的或单个实例,并且以下代码是并行调用的:

MatchResultsForRules(rules, results);
ApplyRules(rules);
MatchResultsForRules()
通过
rule.searchResults.Add(res)
编辑您的
搜索结果。然后在
ApplyRules()
通过
foreach(rule.searchResults中的searchres)
迭代结果之前,您可能会有一个很短的时间间隔。在这段时间间隔内,另一个线程可能正在执行
MatchResultsForRules()
并编辑
searchResults
。更重要的是:如果一个线程试图在另一个线程迭代的同时编辑
搜索结果
,那么最终会出现异常

为了避免这种错误

  • 扪心自问,是否需要存储
    搜索结果
    ,只是为了以后迭代。而不是
    rule.searchResults.Add(res)
    您可以直接调用
    ApplyRule(rule,res)我知道可能还有其他原因或代码部分需要存储结果
  • 考虑是否不能使用共享实例,而是为每个线程提供它自己的实例
  • 使用lock关键字确保这部分代码不会并行执行。这种方法可能会大大降低运行时性能

  • 这个答案基于这样一个假设,即
    规则
    结果
    是共享实例或单实例,并且并行调用以下代码:

    MatchResultsForRules(rules, results);
    ApplyRules(rules);
    
    MatchResultsForRules()
    通过
    rule.searchResults.Add(res)
    编辑您的
    搜索结果。然后在
    ApplyRules()
    通过
    foreach(rule.searchResults中的searchres)
    迭代结果之前,您可能会有一个很短的时间间隔。在这段时间间隔内,另一个线程可能正在执行
    MatchResultsForRules()
    并编辑
    searchResults
    。更重要的是:如果一个线程试图在另一个线程迭代的同时编辑
    搜索结果
    ,那么最终会出现异常

    为了避免这种错误

  • 扪心自问,是否需要存储
    搜索结果
    ,只是为了以后迭代。而不是
    rule.searchResults.Add(res)
    您可以直接调用
    ApplyRule(rule,res)我知道可能还有其他原因或代码部分需要存储结果
  • 考虑是否不能使用共享实例,而是为每个线程提供它自己的实例
  • 使用lock关键字确保这部分代码不会并行执行。这种方法可能会大大降低运行时性能

  • 你怎么知道还有另一个线程把计算搞乱了?不幸的是,我们没有足够的代码来理解正在发生的事情。例如,你能给出调用ApplyRules的代码吗?这是一个由用户击键启动的搜索吗?可能所有rule.SearchResults都引用了相同的列表吗?@MaozHeiferman-你需要提供足够的代码来复制你的问题。您所展示的任何内容都无法解释多线程。您如何知道有另一个线程将计算搞乱?不幸的是,我们没有足够的代码来理解正在发生的事情。例如,你能给出调用ApplyRules的代码吗?这是一个由用户击键启动的搜索吗?可能所有rule.SearchResults都引用了相同的列表吗?@MaozHeiferman-你需要提供足够的代码来复制你的问题。您所显示的任何内容都无法解释有关多线程的任何内容。