简体   繁体   English

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

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

I'm trying to write a C# function to count broken links on a webpage using http requests. 我正在尝试编写一个C#函数来计算使用http请求的网页上的损坏链接。 Since i want to make this quick, i create a thread for each request, and then simply increase the counter in the threads. 由于我想快速执行此操作,因此我为每个请求创建一个线程,然后简单地增加线程中的计数器。 My problem is, the counters stays on 0 at the end, although i know there are several broken links on the website. 我的问题是,尽管我知道网站上有几个断开的链接,但计数器最后仍保持为0。 Seems like the threads are not setting the variables in the main thread. 好像线程没有在主线程中设置变量。

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

I have searched on the internet for hours, tried volatile variables, but nothing seems to work. 我已经在互联网上搜索了几个小时,尝试了volatile变量,但似乎没有任何效果。 How could i force the threads to set the variables in the main thread? 我如何强制线程在主线程中设置变量?

The counter does not stay at 0 - the problems are deeper AND easier. 计数器不保持为0-问题更深,更容易。

  • ++ is not atomic and ++不是原子的
  • C# compiler and runtime can optimize our the read access away. C#编译器和运行时可以优化我们的读取访问权限。

Bes thing: use the Interlocked class method's to increase AND read the class. Bes的事情:使用Interlocked类方法来增加和读取类。 Finished. 成品。 They use an atomic API AND are made for multi threaded operations. 它们使用原子API,并且专为多线程操作而设计。

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

There are two main issues in your code: 您的代码中有两个主要问题:

  • You are not waiting for all the threads to complete before showing the result. 在显示结果之前,您不必等待所有线程完成。
  • ++ is not thread safe, you should use Interlocked.Increment to atomically increment the counter. ++不是线程安全的,您应该使用Interlocked.Increment原子地递增计数器。

You could use Task from the .Net framework to do this easily. 您可以使用.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.

相关问题 如何将此C#工作线程代码与主线程中的共享数据变量分离? - How can I decouple this C# worker thread code from the main thread for shared data variables? 如何在C#中的主线程和后台线程之间切换? - How can I switch between main and background thread in C#? C#:如何通过从另一个线程以某种方式发出信号来强制从主线程“调用”一个方法 - C#: How to force "calling" a method from the main thread by signaling in some way from another thread C#:如何从另一个线程访问主UI线程中的整数? - C#: How do you access an integer in the main UI thread from another thread? C#如何从另一个线程关闭主UI线程上的Windows窗体 - C# How to close a windows form on the main UI thread from another thread 如何判断一个线程是否是C#中的主线程 - How to tell if a thread is the main thread in C# C#如何将对象从工作线程传递回主线程? - C# How do I pass object back to main thread from worker thread? 如何在C#线程中将visible设置为true值? - How can i set visible to true value in c# thread? 从另一个线程c#访问主要形式的文本框组件 - access to textbox component in main form from another thread c# 如何从C#中的另一个线程调用一个线程? - How to call a thread from another thread in C#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM