C# 子线程完成后,主线程不继续

C# 子线程完成后,主线程不继续,c#,multithreading,manualresetevent,waitone,countdownevent,C#,Multithreading,Manualresetevent,Waitone,Countdownevent,我正在尝试在我的应用程序中使用多线程。方法test5尝试从Internet获取一些内容,而main线程在继续其他工作之前等待所有线程完成 但是我的main线程在调用test5后没有返回,我的控制台行在内部完成和线程都恢复了从未到达 我如何解决这个问题 class Program { static void Main(string[] args) { string[] url = { "http://...", "http:/

我正在尝试在我的应用程序中使用多线程。方法
test5
尝试从Internet获取一些内容,而
main
线程在继续其他工作之前等待所有线程完成

但是我的
main
线程在调用
test5
后没有返回,我的控制台行
在内部完成
线程都恢复了从未到达

我如何解决这个问题

class Program
{
    static void Main(string[] args)
    {
        string[] url =
        {
            "http://...", "http://...", "http://...", "http://...", "http://..."
        };

        test5(url); 
        Console.WriteLine("thread all got back!!");

        // Do some other work after all threads come back
        Console.ReadLine();
    }

    private static void test5(string[] _url)
    {
        int numThreads = _url.Length;
        ManualResetEvent resetEvent = new ManualResetEvent(false);
        int toProcess = numThreads;

        for (int i = 0; i < numThreads - 1; i++)
        {
            new Thread( delegate() {
                testWebWorking(_url[i]);
                if (Interlocked.Decrement(ref toProcess) == 0)
                    resetEvent.Set();
            }).Start();
        }
        resetEvent.WaitOne();
        Console.WriteLine("Done inside!!");
    }

    private static void test6(string[] _url)
    {
        int numThreads = _url.Length;
        var countdownEvent = new CountdownEvent(numThreads);

        for (int i = 0; i < numThreads - 1; i++)
        {
            new Thread(delegate() {
                testWebWorking(_url[i]);
                countdownEvent.Signal();
            }).Start();
        }
        countdownEvent.Wait();
        Console.WriteLine("Done inside!!");
    }

    private static void testWebWorking(object url)
    {
        Console.WriteLine("start {0}", Thread.CurrentThread.ManagedThreadId);
        string uri = (string)url;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        request.KeepAlive = true;
        request.Timeout = 5000;
        request.ReadWriteTimeout = 5000;
        request.Proxy = null;

        try
        {
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                //Console.WriteLine(response.ContentType + "; uri = " + uri);
                Stream receiveStream = response.GetResponseStream();
                Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
                // Pipes the stream to a higher level stream reader with the required encoding format. 
                StreamReader readStream = new StreamReader(receiveStream, encode);
                //Console.WriteLine("\r\nResponse stream received.");
                Char[] read = new Char[256];
                // Reads 256 characters at a time.    
                int count = readStream.Read(read, 0, 256);
                //Console.WriteLine("HTML...\r\n");
                String str = "";
                while (count > 0)
                {
                    // Dumps the 256 characters on a string and displays the string to the console.
                    str = new String(read, 0, count);
                    //Console.Write(str);
                    count = readStream.Read(read, 0, 256);
                }
                //Console.WriteLine(str);
                // Releases the resources of the response.
                response.Close();
                // Releases the resources of the Stream.
                readStream.Close();

                Console.WriteLine("end {0}", Thread.CurrentThread.ManagedThreadId);
            }
        }
        catch (WebException ex)
        {
            //Console.WriteLine(ex.GetBaseException().ToString() );
            //Console.WriteLine(url);
            Console.WriteLine("time out !!");
        }
        finally
        {
            request.Abort();
            request = null;
            GC.Collect();
        }
    }
}
类程序
{
静态void Main(字符串[]参数)
{
字符串[]url=
{
"http://...", "http://...", "http://...", "http://...", "http://..."
};
test5(url);
WriteLine(“线程全部返回!!”;
//在所有线程返回后执行其他一些工作
Console.ReadLine();
}
私有静态void test5(字符串[]\u url)
{
int numThreads=\u url.Length;
ManualResetEvent resetEvent=新的ManualResetEvent(错误);
int-toProcess=numThreads;
for(inti=0;i0)
{
//将256个字符转储到字符串中,并将该字符串显示到控制台。
str=新字符串(读取,0,计数);
//控制台写入(str);
count=readStream.Read(Read,0,256);
}
//控制台写入线(str);
//释放响应的资源。
response.Close();
//释放流的资源。
readStream.Close();
WriteLine(“end{0}”,Thread.CurrentThread.ManagedThreadId);
}
}
捕获(WebException ex)
{
//WriteLine(例如GetBaseException().ToString());
//Console.WriteLine(url);
Console.WriteLine(“超时!!”);
}
最后
{
request.Abort();
请求=null;
GC.Collect();
}
}
}
看看这个:

for (int i = 0; i < numThreads - 1; i++)
在这里,您将在委托中捕获变量
i
,因此当您执行它时,它将具有
i
所具有的任何值。您可以多次测试同一URL,并跳过其他URL。相反,您应该将
i
的值复制到循环中的变量中,以便每次捕获不同的变量:

// Fixed the loop boundary as well
for (int i = 0; i < numThreads; i++)
{
    int copy = i;
    new Thread(() => // Use a lambda expression for brevity
    {
        // Fix naming convention for method name, too...
        TestWebWorking(_url[copy]);
        if (Interlocked.Decrement(ref toProcess) == 0))
        {
            resetEvent.Set();
        }
    }).Start()
}

或者,使用
Parallel.ForEach
会更简单,它正是为这类事情而设计的。

谢谢,它工作得很好。这只是在演示我的问题,所以我只是用for循环来展示它。在实际代码中,我使用了多个while循环,因为实际情况有点复杂。在我的实际代码中,numThreads**是未知的,我在彼此之间有多个while循环**直到所有循环完成,numThreads才知道…如何解决它?我应该在完成所有复杂的while循环后启动线程吗?或者我可以在循环中启动线程,如上图所示?
// Fixed the loop boundary as well
for (int i = 0; i < numThreads; i++)
{
    int copy = i;
    new Thread(() => // Use a lambda expression for brevity
    {
        // Fix naming convention for method name, too...
        TestWebWorking(_url[copy]);
        if (Interlocked.Decrement(ref toProcess) == 0))
        {
            resetEvent.Set();
        }
    }).Start()
}
private static void TestWithResetEvent(string[] urls)
{
    ManualResetEvent resetEvent = new ManualResetEvent(false);
    int counter = urls.Length;

    foreach (string url in urls)
    {
        string copy = url;
        Thread t = new Thread(() =>
        {
            TestWebWorking(copy);
            if (Interlocked.Decrement(ref toProcess) == 0))
            {
                resetEvent.Set();
            }
        });
        t.Start();
    }
    resetEvent.WaitOne();
    Console.WriteLine("Done inside!!");
}