如何在 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());
    }

我在互联网上搜索了几个小时,尝试了易变变量,但似乎没有任何效果。如何强制线程在主线程中设置变量?

如何在 C# 中从另一个线程在主线程中设置变量

在 .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,并且是为多线程操作而制作的。