遇到意外的联锁行为?
我正在编写一个网络链接检查程序,并遇到了我无法解释的 Interlocked 行为。首先,这是代码的删节版本:
public class LinkCheckProcessor
{
private long _remainingLinks;
public event EventHandler<LinksCheckedEventArgs> AllLinksChecked;
private void ProcessLinks(List<Link> links)
{
foreach (Link link in links)
{
ProcessLink(link);
}
}
private void ProcessLink(Link link)
{
var linkChecker = new LinkChecker(link);
linkChecker.LinkChecked += LinkChecked;
Interlocked.Increment(ref _remainingLinks);
#if DEBUG
System.Diagnostics.Debug.WriteLine(String.Format("LinkChecker: Checking link '{0}', remaining: {1}", link, Interlocked.Read(ref _remainingLinks)));
#endif
linkChecker.Check();
}
void LinkChecked(object sender, LinkCheckedEventArgs e)
{
var linkChecker = (LinkChecker)sender;
Interlocked.Decrement(ref _remainingLinks);
#if DEBUG
System.Diagnostics.Debug.WriteLine(String.Format("LinkChecker: Checked link '{0}', remaining: {1}", linkChecker.Link, Interlocked.Read(ref _remainingLinks)));
#endif
if (Interlocked.Read(ref _remainingLinks) == 0)
{
OnAllLinksChecked(new LinksCheckedEventArgs(this.BatchId, this.Web.Url));
}
}
}
我在调试输出中看到的是这样的内容:
- LinkChecker: Checked link 'http://serverfault.com', left: 1
- LinkChecker: Checked link 'http://superuser .com',剩余:0
- LinkChecker:检查链接“http://stackoverflow.com”,剩余:-1
我不明白为什么(在某些代码运行中)_remainingLinks
是变得消极。这还会产生副作用,导致过早触发 AllLinksChecked
事件。 (顺便说一句,上面的代码包含 _remainingLinks
唯一被触及的地方。)
我做错了什么?
I'm writing a web link checker program and encountering behaviour with Interlocked that I can't explain. First, here's an abridged version of the code:
public class LinkCheckProcessor
{
private long _remainingLinks;
public event EventHandler<LinksCheckedEventArgs> AllLinksChecked;
private void ProcessLinks(List<Link> links)
{
foreach (Link link in links)
{
ProcessLink(link);
}
}
private void ProcessLink(Link link)
{
var linkChecker = new LinkChecker(link);
linkChecker.LinkChecked += LinkChecked;
Interlocked.Increment(ref _remainingLinks);
#if DEBUG
System.Diagnostics.Debug.WriteLine(String.Format("LinkChecker: Checking link '{0}', remaining: {1}", link, Interlocked.Read(ref _remainingLinks)));
#endif
linkChecker.Check();
}
void LinkChecked(object sender, LinkCheckedEventArgs e)
{
var linkChecker = (LinkChecker)sender;
Interlocked.Decrement(ref _remainingLinks);
#if DEBUG
System.Diagnostics.Debug.WriteLine(String.Format("LinkChecker: Checked link '{0}', remaining: {1}", linkChecker.Link, Interlocked.Read(ref _remainingLinks)));
#endif
if (Interlocked.Read(ref _remainingLinks) == 0)
{
OnAllLinksChecked(new LinksCheckedEventArgs(this.BatchId, this.Web.Url));
}
}
}
What I'm seeing in the debug output are things like:
- LinkChecker: Checked link 'http://serverfault.com', remaining: 1
- LinkChecker: Checked link 'http://superuser.com', remaining: 0
- LinkChecker: Checked link 'http://stackoverflow.com', remaining: -1
I don't understand why (in some code runs) _remainingLinks
is becoming negative. This is also having the side effect of causing the AllLinksChecked
event from being fired too early. (By the way, the code above contains the only places that _remainingLinks
is touched.)
What am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的
AllLinksChecked
逻辑肯定是错误的,因为计数器可能会变为0->1
、1->0
、0- >1
、1->0
、0->1
、1->0
从而达到零多次。但我不明白计数怎么会变成负数。这些是
_remainingLinks
出现在您的代码中的唯一位置吗?第一个问题可以通过从 ProcessLink 中删除增量代码并在开始循环之前让 ProcessLinks 将计数初始化为 links.Count 来解决:
当
ProcessLinks
运行时,links
参数不是从其他线程写入的,是吗?Your
AllLinksChecked
logic is definitely wrong, since the counter could go0->1
,1->0
,0->1
,1->0
,0->1
,1->0
and thus reach zero multiple times.But I don't see how the count could ever go negative. Are these the only places that
_remainingLinks
appears in your code?The first problem could be fixed just by removing the increment code from
ProcessLink
and havingProcessLinks
initialize the count tolinks.Count
before starting the loop:The
links
argument isn't being written from other threads whileProcessLinks
is running, is it?我将冒险提出,
LinkChecker
会为调用Check()
触发多个事件。除此之外,我看不出该值怎么可能变成负值。I'm going to go out on a limb and propose that
LinkChecker
is firing more than one event for a call toCheck()
. Short of this, I can't see how the value could possibly go negative.