如何在 C# 中从另一个线程在主线程中设置变量
本文关键字:线程 变量 设置 另一个 | 更新日期: 2023-09-27 18:34:34
我正在尝试编写一个 C# 函数来使用 http 请求计算网页上的断开链接。由于我想快速完成此操作,因此我为每个请求创建一个线程,然后简单地增加线程中的计数器。我的问题是,计数器在最后保持在 0 上,尽管我知道网站上有几个断开的链接。似乎线程没有在主线程中设置变量。
public volatile int found;
public volatile int notfound;
public void GetBrokenLinks(WebBrowser website)
{
HtmlElementCollection links = website.Document.GetElementsByTagName("a");
foreach (HtmlElement element in links)
{
string link = element.GetAttribute("href").ToString();
Uri urlCheck = new Uri(link);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlCheck);
request.Timeout = 10000;
try
{
Thread link_checher_thread = new Thread(delegate ()
{
HttpWebResponse response;
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
response.Dispose();
found++;
}
else if (response.StatusCode == HttpStatusCode.NotFound)
{
response.Dispose();
notfound++;
}
});
link_checher_thread.IsBackground = true;
link_checher_thread.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
MessageBox.Show(found.ToString() + ", " + notfound.ToString());
}
我在互联网上搜索了几个小时,尝试了易变变量,但似乎没有任何效果。如何强制线程在主线程中设置变量?
在 .NET 中增加共享计数器的正确方法是通过 System.Threading.Interlocked.Increment(ref found)
代码中有两个主要问题:
- 您不会等待所有线程完成,然后再显示结果。
- ++ 不是线程安全的,您应该使用 Interlocked.Increment 以原子方式递增计数器。
您可以使用 .Net 框架中的 Task 轻松完成此操作。
public int found;
public int notfound;
public void GetBrokenLinks(WebBrowser website)
{
HtmlElementCollection links = website.Document.GetElementsByTagName("a");
List<Task> tasks = new List<Task>();
foreach (string element in links)
{
string link = element.GetAttribute("href").ToString();
tasks.Add(Task.Factory.StartNew(() =>
{
Uri urlCheck = new Uri(link);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlCheck);
request.Timeout = 10000;
HttpWebResponse response;
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
response.Dispose();
Interlocked.Increment(ref found);
}
else if (response.StatusCode == HttpStatusCode.NotFound)
{
response.Dispose();
Interlocked.Increment(ref notfound);
}
}
));
}
try
{
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae)
{
ae.Handle((e) => { MessageBox.Show(e.ToString()); return true; });
}
MessageBox.Show(found.ToString() + ", " + notfound.ToString());
}
计数器不会停留在 0 - 问题更深、更容易。
- ++不是原子的,并且
- C#编译器和运行时可以优化我们的读取访问。
Bes 事情:使用互锁类方法增加和读取类。 完成。它们使用原子 API,并且是为多线程操作而制作的。