繁体   English   中英

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

[英]How can i set variables in the main thread from another thread in C#?

我正在尝试编写一个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());
    }

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

计数器不保持为0-问题更深,更容易。

  • ++不是原子的
  • C#编译器和运行时可以优化我们的读取访问权限。

Bes的事情:使用Interlocked类方法来增加和读取类。 成品。 它们使用原子API,并且专为多线程操作而设计。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM