偶尔,会有另一个线程开始执行我的代码。
// 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,并且按照动作的顺序看到了混乱,当然还有两个不同的线程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);
}
}
}
我只是想更好地理解这个问题,以便将来不再重复此错误。
答案 0 :(得分:0)
此答案基于以下假设:rules
和results
是共享或单例实例,并且以下代码被并行调用:
MatchResultsForRules(rules, results);
ApplyRules(rules);
MatchResultsForRules()
通过searchResults
编辑rule.searchResults.Add(res)
。这样一来,您在ApplyRules()
上通过foreach(SearchResult res in rule.searchResults)
遍历结果之前可能会有短暂的时间间隔。在这段时间内,另一个线程可能正在执行MatchResultsForRules()
并编辑searchResults
。更重要的是:如果一个线程尝试在另一个迭代过程中同时编辑searchResults
,那么您将以Exception结尾。
为避免此类错误
searchResults
以便稍后进行迭代。我知道,可能有其他原因或代码部分可能需要存储结果,而不是直接rule.searchResults.Add(res);
来调用ApplyRule(rule, res);
。lock(yourSharedReadonlyLockObject)
{
MatchResultsForRules(rules, results);
ApplyRules(rules);
}