Web リンク チェッカー プログラムを作成していて、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: リンク 'http://serverfault.com' をチェックしました。残り: 1
- LinkChecker: リンク 'http://superuser.com' をチェックしました。残り: 0
- LinkChecker: リンク 'http://stackoverflow.com' をチェック、残り: -1
_remainingLinks
(一部のコード実行で)が負になる理由がわかりません。AllLinksChecked
これには、イベントの発生が早すぎるという副作用もあります。(ちなみに、上記のコードには、_remainingLinks
触れている場所のみが含まれています。)
私は何を間違っていますか?