我有一个文本文件,我读取到一个字符串content。要识别要进一步处理的文本正文,我将获取字符串中关键字的索引,然后将“启动”索引设置为找到的最小索引。
我和Parallel.ForEach试过这个..。
ConcurrentBag<int> indexes = new();
int index;
switch (Case)
{
case 1:
Parallel.ForEach(KeywordTypes.GetImplementedNamedObjects(), inos =>
{
index = content.IndexOf($"/begin {inos}");
index = index == -1 ? content.Length : index;
indexes.Add(index);
});
index = indexes.Min();
return index;..。以及使用foreach
foreach (string inos in KeywordTypes.GetImplementedNamedObjects())
{
index = content.IndexOf($"/begin {inos}");
index = index == -1 ? content.Length : index;
indexes.Add(index);
}
index = indexes.Min();
return index;其中,foreach产生预期的结果,但Parallel.ForEach没有。
为什么我的代码不安全?
发布于 2021-09-13 06:34:59
这里只有一个index变量,因为它是“捕获”的。这意味着多个线程可以为它争吵,而不是每个线程都有自己的版本。
考虑:
线程A计算index = content.IndexOf($"/begin {inos}");
index = content.IndexOf($"/begin {inos}"); - oops,线程A的版本刚刚得到了overwritten
的index计算index = index == -1 ? content.Length : index;
重点是:一个值由于线程争用而丢失。
只需移动index的声明就可以修复这个问题:
Parallel.ForEach(KeywordTypes.GetImplementedNamedObjects(), inos =>
{
var index = content.IndexOf($"/begin {inos}");
...从根本上说,变量的作用域是由其声明的位置定义的。如果一个变量在本地方法/ lambda之外声明,编译器会尊重您所要求的内容,并且该变量在该本地方法/ lambda的所有用途之间共享;如果它在本地方法/lambda中声明,则该生存期是该调用的本地变量,调用方之间不共享任何状态。
如果您想确保您没有意外泄漏状态,那么lambda上的static修饰符就可以实现这一点,尽管它也可以防止访问indexes,所以.可能不是你在这里需要的。
https://stackoverflow.com/questions/69158225
复制相似问题