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

时间:2016-02-13 00:05:27

标签: c# multithreading

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

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

3 个答案:

答案 0 :(得分:2)

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

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

Bes thing:使用Interlocked类方法来增加和读取类。成品。它们使用原子API并用于多线程操作。

答案 1 :(得分:2)

在.NET中增加共享计数器的正确方法是通过System.Threading.Interlocked.Increment(ref found)

答案 2 :(得分:1)

您的代码中存在两个主要问题:

  • 在显示结果之前,您不是在等待所有线程完成。
  • ++不是线程安全的,你应该使用Interlocked.Increment以原子方式递增计数器。

您可以使用.Net框架中的任务轻松完成此任务。

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