【问题标题】:Why a new thread executed without creating a new one?为什么要执行一个新线程而不创建一个新线程?
【发布时间】:2019-08-26 13:54:34
【问题描述】:

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

// 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);
      }
   }
}

我知道还有另一个线程,因为一旦我看到问题发生(计算不匹配),我打印了一个详细的日志,包括每个操作的线程 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);
      }
   }
}

我只是想更好地理解这个问题,以免以后重蹈覆辙。

【问题讨论】:

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

标签: c# multithreading thread-safety


【解决方案1】:

此答案基于rulesresults 是共享实例或单例实例并且并行调用以下代码的假设:

MatchResultsForRules(rules, results);
ApplyRules(rules);

MatchResultsForRules() 通过rule.searchResults.Add(res) 编辑您的searchResults。那么在ApplyRules() 通过foreach(SearchResult res in rule.searchResults) 迭代结果之前,您可能会有很短的时间间隔。在这段时间间隔内,另一个线程可能正在执行MatchResultsForRules() 并编辑searchResults。更重要的是:如果一个线程尝试编辑searchResults,同时另一个线程对其进行迭代,您最终会遇到异常。

为了避免此类错误

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

【讨论】:

    猜你喜欢
    • 2011-08-03
    • 2020-11-01
    • 2013-07-19
    • 2013-12-31
    • 1970-01-01
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多